timr 0.1.0.pre.dev.1 → 0.1.0.pre.dev.5
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/Makefile +0 -4
- data/bin/timr +3 -5
- data/lib/timr.rb +1 -0
- data/lib/timr/stack.rb +8 -6
- data/lib/timr/task.rb +69 -24
- data/lib/timr/timr.rb +158 -81
- data/lib/timr/track.rb +84 -0
- data/lib/timr/version.rb +2 -2
- data/lib/timr/window.rb +36 -15
- data/lib/timr/window_help.rb +3 -0
- data/lib/timr/window_tasks.rb +3 -1
- data/lib/timr/window_test.rb +4 -0
- data/lib/timr/window_timeline.rb +26 -1
- metadata +3 -3
- data/bin/dev +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4157f4d824d2cadedc511f421b488656ac6a9640
|
4
|
+
data.tar.gz: f859883d4ee1a270a61653e4e6c063bacd5f9969
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 461b4bccfd4fd85530a1d570eb8feac64c4f21e47cb2846e18688bbfe8a053e75934f7444f9fa30bb1cc5983b8f089615e316cecfc2f3cf0114717eda371c5cd
|
7
|
+
data.tar.gz: ab112bd2d0e900913dac25283681c2eddf21ae381e78b2299b7d42836baab4e8cd7f4ab6ab2a94685ff22eb9878d4c73116f4c3297622e4a970981ee99cad133
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/Makefile
CHANGED
data/bin/timr
CHANGED
@@ -31,8 +31,6 @@ end
|
|
31
31
|
ARGV << '-h' if ARGV.count == 0
|
32
32
|
opts.parse(ARGV)
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
# timr.run
|
38
|
-
# timr.close
|
34
|
+
timr = TheFox::Timr::Timr.new(@options[:dir])
|
35
|
+
timr.run
|
36
|
+
timr.close
|
data/lib/timr.rb
CHANGED
data/lib/timr/stack.rb
CHANGED
@@ -34,7 +34,7 @@ module TheFox
|
|
34
34
|
@tasks.map{ |task|
|
35
35
|
status = task.status
|
36
36
|
status = '*' if task == @task
|
37
|
-
"#{status} #{task
|
37
|
+
"#{status} #{task}"
|
38
38
|
}
|
39
39
|
end
|
40
40
|
|
@@ -63,11 +63,13 @@ module TheFox
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def push(task)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
if !@tasks.include?(task)
|
67
|
+
@task.stop if has_task?
|
68
|
+
|
69
|
+
@task = task
|
70
|
+
@task.start
|
71
|
+
@tasks << @task
|
72
|
+
end
|
71
73
|
end
|
72
74
|
|
73
75
|
end
|
data/lib/timr/task.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
|
2
2
|
require 'time'
|
3
|
-
#require 'yaml'
|
4
3
|
require 'yaml/store'
|
5
4
|
require 'uuid'
|
6
5
|
|
@@ -23,8 +22,9 @@ module TheFox
|
|
23
22
|
'created' => Time.now.strftime(TIME_FORMAT),
|
24
23
|
'modified' => Time.now.strftime(TIME_FORMAT),
|
25
24
|
}
|
26
|
-
@
|
25
|
+
@track = nil
|
27
26
|
@timeline = []
|
27
|
+
@timeline_diff_total = nil
|
28
28
|
|
29
29
|
@path = path
|
30
30
|
if !@path.nil?
|
@@ -36,11 +36,8 @@ module TheFox
|
|
36
36
|
content = YAML::load_file(path)
|
37
37
|
@meta = content['meta']
|
38
38
|
@timeline = content['timeline']
|
39
|
-
.map{ |
|
40
|
-
|
41
|
-
'b' => Time.parse(time_raw['b']),
|
42
|
-
'e' => Time.parse(time_raw['e']),
|
43
|
-
}
|
39
|
+
.map{ |track_raw|
|
40
|
+
Track.from_h(self, track_raw)
|
44
41
|
}
|
45
42
|
end
|
46
43
|
|
@@ -49,16 +46,8 @@ module TheFox
|
|
49
46
|
path = File.expand_path("task_#{@meta['id']}.yml", basepath)
|
50
47
|
|
51
48
|
timeline_c = @timeline
|
52
|
-
.
|
53
|
-
|
54
|
-
time = time.clone
|
55
|
-
if !time['b'].nil?
|
56
|
-
time['b'] = time['b'].strftime(TIME_FORMAT)
|
57
|
-
end
|
58
|
-
if !time['e'].nil?
|
59
|
-
time['e'] = time['e'].strftime(TIME_FORMAT)
|
60
|
-
end
|
61
|
-
time
|
49
|
+
.map{ |track|
|
50
|
+
track.to_h
|
62
51
|
}
|
63
52
|
|
64
53
|
store = YAML::Store.new(path)
|
@@ -106,22 +95,25 @@ module TheFox
|
|
106
95
|
@meta['description'] = description == '' ? nil : description
|
107
96
|
end
|
108
97
|
|
98
|
+
def timeline
|
99
|
+
@timeline
|
100
|
+
end
|
101
|
+
|
109
102
|
def start
|
110
103
|
if !running?
|
111
104
|
changed
|
112
|
-
@
|
113
|
-
|
114
|
-
'e' => nil, # end
|
115
|
-
}
|
116
|
-
@timeline << @time
|
105
|
+
@track = Track.new(self)
|
106
|
+
@timeline << @track
|
117
107
|
end
|
118
108
|
@status = :running
|
119
109
|
end
|
120
110
|
|
121
111
|
def stop
|
122
|
-
if running? && !@
|
112
|
+
if running? && !@track.nil?
|
123
113
|
changed
|
124
|
-
@
|
114
|
+
@track.end = Time.now
|
115
|
+
@track = nil
|
116
|
+
@timeline_diff_total = nil
|
125
117
|
end
|
126
118
|
@status = :stop
|
127
119
|
end
|
@@ -138,6 +130,59 @@ module TheFox
|
|
138
130
|
name
|
139
131
|
end
|
140
132
|
|
133
|
+
def to_list_s
|
134
|
+
name
|
135
|
+
end
|
136
|
+
|
137
|
+
def run_time_track
|
138
|
+
hours = 0
|
139
|
+
minutes = 0
|
140
|
+
seconds = 0
|
141
|
+
|
142
|
+
if !@track.nil?
|
143
|
+
diff = (Time.now - @track.begin).to_i.abs
|
144
|
+
hours = diff / 3600
|
145
|
+
|
146
|
+
diff -= hours * 3600
|
147
|
+
minutes = diff / 60
|
148
|
+
|
149
|
+
diff -= minutes * 60
|
150
|
+
seconds = diff
|
151
|
+
end
|
152
|
+
|
153
|
+
[hours, minutes, seconds]
|
154
|
+
end
|
155
|
+
|
156
|
+
def run_time_total
|
157
|
+
# Cache all other tracks.
|
158
|
+
if @timeline_diff_total.nil?
|
159
|
+
@timeline_diff_total = @timeline
|
160
|
+
.select{ |track| track != @track }
|
161
|
+
.map{ |track| track.diff }
|
162
|
+
.inject(:+)
|
163
|
+
end
|
164
|
+
|
165
|
+
hours = 0
|
166
|
+
minutes = 0
|
167
|
+
seconds = 0
|
168
|
+
|
169
|
+
track_diff = 0
|
170
|
+
if !@track.nil?
|
171
|
+
track_diff = (Time.now - @track.begin).to_i.abs
|
172
|
+
end
|
173
|
+
|
174
|
+
diff = @timeline_diff_total.to_i + track_diff
|
175
|
+
hours = diff / 3600
|
176
|
+
|
177
|
+
diff -= hours * 3600
|
178
|
+
minutes = diff / 60
|
179
|
+
|
180
|
+
diff -= minutes * 60
|
181
|
+
seconds = diff
|
182
|
+
|
183
|
+
[hours, minutes, seconds]
|
184
|
+
end
|
185
|
+
|
141
186
|
end
|
142
187
|
|
143
188
|
end
|
data/lib/timr/timr.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
|
2
2
|
require 'curses'
|
3
3
|
require 'time'
|
4
|
+
require 'fileutils'
|
4
5
|
|
5
6
|
module TheFox
|
6
7
|
module Timr
|
@@ -25,27 +26,29 @@ module TheFox
|
|
25
26
|
tasks_load
|
26
27
|
|
27
28
|
@window = nil
|
28
|
-
@window_timeline = TimelineWindow.new
|
29
29
|
@window_help = HelpWindow.new
|
30
30
|
@window_test = TestWindow.new
|
31
31
|
|
32
32
|
@window_tasks = TasksWindow.new
|
33
33
|
@window_tasks.tasks = @tasks
|
34
|
+
|
35
|
+
@window_timeline = TimelineWindow.new
|
36
|
+
@window_timeline.tasks = @tasks
|
34
37
|
end
|
35
38
|
|
36
39
|
def init_dirs
|
37
40
|
if !Dir.exist?(@base_dir_path)
|
38
|
-
|
41
|
+
FileUtils.mkdir_p(@base_dir_path)
|
39
42
|
end
|
40
43
|
if !Dir.exist?(@data_dir_path)
|
41
|
-
|
44
|
+
FileUtils.mkdir_p(@data_dir_path)
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
45
48
|
def tasks_load
|
46
49
|
Dir.chdir(@data_dir_path) do
|
47
50
|
Dir['task_*.yml'].each do |file_name|
|
48
|
-
puts "file: '#{file_name}'"
|
51
|
+
#puts "file: '#{file_name}'"
|
49
52
|
task = Task.new(file_name)
|
50
53
|
@tasks[task.id] = task
|
51
54
|
end
|
@@ -66,7 +69,7 @@ module TheFox
|
|
66
69
|
end
|
67
70
|
end
|
68
71
|
|
69
|
-
def
|
72
|
+
def ui_init_curses
|
70
73
|
Curses.noecho
|
71
74
|
Curses.timeout = TIMEOUT
|
72
75
|
Curses.curs_set(0)
|
@@ -81,7 +84,7 @@ module TheFox
|
|
81
84
|
Curses.init_pair(Curses::COLOR_YELLOW, Curses::COLOR_BLACK, Curses::COLOR_YELLOW)
|
82
85
|
end
|
83
86
|
|
84
|
-
def
|
87
|
+
def ui_title_line
|
85
88
|
title = "#{NAME} #{VERSION} -- #{@base_dir_name}"
|
86
89
|
if Curses.cols <= title.length + 1
|
87
90
|
title = "#{NAME} #{VERSION}"
|
@@ -97,7 +100,7 @@ module TheFox
|
|
97
100
|
end
|
98
101
|
end
|
99
102
|
|
100
|
-
def
|
103
|
+
def ui_status_text(text, attrn = Curses::A_NORMAL)
|
101
104
|
line_nr = Curses.lines - 1
|
102
105
|
|
103
106
|
Curses.setpos(line_nr, 0)
|
@@ -109,12 +112,16 @@ module TheFox
|
|
109
112
|
Curses.refresh
|
110
113
|
end
|
111
114
|
|
112
|
-
def
|
115
|
+
def ui_status_text_error(text)
|
116
|
+
ui_status_text(text, Curses.color_pair(Curses::COLOR_RED) | Curses::A_BOLD)
|
117
|
+
end
|
118
|
+
|
119
|
+
def ui_status_input(text)
|
113
120
|
Curses.echo
|
114
121
|
Curses.timeout = -1
|
115
122
|
Curses.curs_set(1)
|
116
123
|
|
117
|
-
|
124
|
+
ui_status_text(text)
|
118
125
|
|
119
126
|
input = ''
|
120
127
|
abort = false
|
@@ -144,7 +151,7 @@ module TheFox
|
|
144
151
|
input
|
145
152
|
end
|
146
153
|
|
147
|
-
def
|
154
|
+
def ui_status_line(init = false)
|
148
155
|
line_nr = Curses.lines - 2
|
149
156
|
|
150
157
|
Curses.attron(Curses.color_pair(Curses::COLOR_YELLOW) | Curses::A_NORMAL) do
|
@@ -156,9 +163,13 @@ module TheFox
|
|
156
163
|
|
157
164
|
Curses.setpos(line_nr, COL)
|
158
165
|
if @stack.has_task?
|
159
|
-
|
166
|
+
status = @stack.task.status
|
167
|
+
run_time_track = '%4d:%02d:%02d' % @stack.task.run_time_track
|
168
|
+
run_time_total = '%4d:%02d:%02d' % @stack.task.run_time_total
|
169
|
+
|
170
|
+
Curses.addstr("#{status} #{run_time_track} #{run_time_total}")
|
160
171
|
else
|
161
|
-
Curses.addstr(TASK_NO_TASK_LOADED_C)
|
172
|
+
Curses.addstr("#{TASK_NO_TASK_LOADED_C} ----:--:-- ----:--:--")
|
162
173
|
end
|
163
174
|
|
164
175
|
if Curses.cols > MIN_COLS
|
@@ -183,13 +194,13 @@ module TheFox
|
|
183
194
|
Curses.refresh
|
184
195
|
end
|
185
196
|
|
186
|
-
def
|
197
|
+
def ui_window_show(window)
|
187
198
|
@window = window
|
188
|
-
|
199
|
+
ui_window_refresh
|
189
200
|
end
|
190
201
|
|
191
|
-
def
|
192
|
-
max_lines =
|
202
|
+
def ui_window_refresh
|
203
|
+
max_lines = ui_content_length
|
193
204
|
(1..max_lines).each do |line_nr|
|
194
205
|
Curses.setpos(line_nr, 0)
|
195
206
|
Curses.clrtoeol
|
@@ -198,14 +209,18 @@ module TheFox
|
|
198
209
|
if !@window.nil?
|
199
210
|
line_nr = 1
|
200
211
|
@window.content_refresh
|
201
|
-
page_length = @window.page_length
|
202
212
|
current_line = @window.current_line
|
203
213
|
max_line_len = Curses.cols - 2
|
204
214
|
@window.page.each do |line_object|
|
205
215
|
is_cursor = line_nr == @window.cursor
|
206
216
|
|
207
|
-
line_text =
|
208
|
-
|
217
|
+
line_text = ''
|
218
|
+
if line_object.is_a?(Task) || line_object.is_a?(Track)
|
219
|
+
line_text = line_object.to_list_s
|
220
|
+
else
|
221
|
+
line_text = line_object.to_s
|
222
|
+
end
|
223
|
+
|
209
224
|
if line_text.length > max_line_len
|
210
225
|
cut = line_text.length - max_line_len + 4
|
211
226
|
line_text = "#{line_text[0..-cut]}..."
|
@@ -213,16 +228,22 @@ module TheFox
|
|
213
228
|
|
214
229
|
rest = Curses.cols - line_text.length - COL
|
215
230
|
|
216
|
-
if
|
217
|
-
|
218
|
-
|
219
|
-
Curses.
|
231
|
+
if @window.has_cursor?
|
232
|
+
if is_cursor
|
233
|
+
Curses.setpos(line_nr, 0)
|
234
|
+
Curses.attron(Curses.color_pair(Curses::COLOR_BLUE) | Curses::A_BOLD) do
|
235
|
+
Curses.addstr(' ' * COL + line_text + ' ' * rest)
|
236
|
+
end
|
237
|
+
else
|
238
|
+
Curses.setpos(line_nr, COL)
|
239
|
+
Curses.addstr(line_text)
|
220
240
|
end
|
221
241
|
else
|
222
242
|
Curses.setpos(line_nr, COL)
|
223
243
|
Curses.addstr(line_text)
|
224
244
|
end
|
225
245
|
|
246
|
+
|
226
247
|
line_nr += 1
|
227
248
|
end
|
228
249
|
end
|
@@ -230,28 +251,32 @@ module TheFox
|
|
230
251
|
Curses.refresh
|
231
252
|
end
|
232
253
|
|
233
|
-
def
|
254
|
+
def ui_content_length
|
234
255
|
Curses.lines - RESERVED_LINES - @stack.length
|
235
256
|
end
|
236
257
|
|
237
258
|
def update_content_length
|
238
|
-
cl =
|
259
|
+
cl = ui_content_length
|
239
260
|
|
240
|
-
@window_timeline.content_length = cl
|
241
261
|
@window_help.content_length = cl
|
242
262
|
@window_test.content_length = cl
|
243
263
|
@window_tasks.content_length = cl
|
264
|
+
@window_timeline.content_length = cl
|
265
|
+
end
|
266
|
+
|
267
|
+
def ui_refresh
|
268
|
+
ui_stack_lines_refresh
|
269
|
+
ui_window_refresh
|
244
270
|
end
|
245
271
|
|
246
|
-
def
|
272
|
+
def ui_refresh_all
|
247
273
|
update_content_length
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
window_refresh
|
274
|
+
ui_title_line
|
275
|
+
ui_status_line(true)
|
276
|
+
ui_refresh
|
252
277
|
end
|
253
278
|
|
254
|
-
def
|
279
|
+
def ui_stack_lines_refresh
|
255
280
|
line_nr = Curses.lines - (3 + (@stack.length - 1))
|
256
281
|
|
257
282
|
Curses.attron(Curses.color_pair(Curses::COLOR_BLUE)) do
|
@@ -269,11 +294,46 @@ module TheFox
|
|
269
294
|
Curses.refresh
|
270
295
|
end
|
271
296
|
|
297
|
+
def task_apply(task = nil, push = false)
|
298
|
+
if task.nil?
|
299
|
+
@stack.pop_all
|
300
|
+
else
|
301
|
+
@tasks[task.id] = task
|
302
|
+
if push
|
303
|
+
@stack.push(task)
|
304
|
+
else
|
305
|
+
@stack.pop_all(task)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
window_content_changed
|
310
|
+
ui_stack_lines_refresh
|
311
|
+
ui_window_refresh if !push
|
312
|
+
end
|
313
|
+
|
314
|
+
def task_apply_replace_stack(task)
|
315
|
+
task_apply(task, false)
|
316
|
+
end
|
317
|
+
|
318
|
+
def task_apply_stack_pop_all
|
319
|
+
task_apply(nil, false)
|
320
|
+
end
|
321
|
+
|
322
|
+
def task_apply_push(task)
|
323
|
+
task_apply(task, true)
|
324
|
+
end
|
325
|
+
|
326
|
+
def window_content_changed
|
327
|
+
@window_tasks.content_changed
|
328
|
+
@window_timeline.content_changed
|
329
|
+
end
|
330
|
+
|
272
331
|
def run
|
273
|
-
|
332
|
+
ui_init_curses
|
274
333
|
update_content_length
|
275
|
-
|
276
|
-
|
334
|
+
ui_title_line
|
335
|
+
ui_status_line(true)
|
336
|
+
ui_window_show(@window_timeline)
|
277
337
|
|
278
338
|
loop do
|
279
339
|
key_pressed = Curses.getch
|
@@ -281,96 +341,113 @@ module TheFox
|
|
281
341
|
case key_pressed
|
282
342
|
when Curses::Key::NPAGE
|
283
343
|
@window.next_page if !@window.nil?
|
284
|
-
|
344
|
+
ui_window_refresh
|
285
345
|
when Curses::Key::PPAGE
|
286
346
|
@window.previous_page if !@window.nil?
|
287
|
-
|
347
|
+
ui_window_refresh
|
288
348
|
when Curses::Key::DOWN
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
349
|
+
if !@window.nil? && @window.has_cursor?
|
350
|
+
@window.cursor_next_line
|
351
|
+
|
352
|
+
#ui_status_text("Cursor: #{@window.cursor} c=#{ui_content_length} l=#{@window.current_line} pr=#{@window.page_refreshes} cr=#{@window.content_refreshes}")
|
353
|
+
|
354
|
+
ui_window_refresh
|
355
|
+
end
|
293
356
|
when Curses::Key::UP
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
357
|
+
if !@window.nil? && @window.has_cursor?
|
358
|
+
@window.cursor_previous_line
|
359
|
+
|
360
|
+
#ui_status_text("Cursor: #{@window.cursor} c=#{ui_content_length} l=#{@window.current_line} pr=#{@window.page_refreshes} cr=#{@window.content_refreshes}")
|
361
|
+
|
362
|
+
ui_window_refresh
|
363
|
+
end
|
298
364
|
when Curses::Key::HOME
|
299
365
|
@window.first_page if !@window.nil?
|
300
|
-
|
366
|
+
ui_window_refresh
|
301
367
|
when Curses::Key::END
|
302
368
|
@window.last_page if !@window.nil?
|
303
|
-
|
369
|
+
ui_window_refresh
|
304
370
|
when Curses::Key::RESIZE
|
305
371
|
update_content_length
|
306
|
-
|
372
|
+
ui_status_text("Resizing: #{Curses.lines}x#{Curses.cols}")
|
307
373
|
|
308
374
|
# Refreshing the complete screen while resizing
|
309
375
|
# can make everything slower. So for fast resizing
|
310
376
|
# comment this line.
|
311
|
-
|
377
|
+
ui_refresh_all
|
312
378
|
when 10
|
313
379
|
object = @window.page_object if !@window.nil?
|
380
|
+
|
381
|
+
task = nil
|
382
|
+
if object.is_a?(Task)
|
383
|
+
task = object
|
384
|
+
elsif object.is_a?(Track)
|
385
|
+
task = object.task
|
386
|
+
end
|
387
|
+
|
388
|
+
if task.nil?
|
389
|
+
ui_status_text("Unrecognized object: #{object.class}")
|
390
|
+
else
|
391
|
+
task_apply_replace_stack(task)
|
392
|
+
end
|
393
|
+
when 'b', 'p'
|
394
|
+
object = @window.page_object if !@window.nil?
|
395
|
+
|
396
|
+
task = nil
|
314
397
|
if object.is_a?(Task)
|
315
|
-
|
398
|
+
task = object
|
399
|
+
elsif object.is_a?(Track)
|
400
|
+
task = object.task
|
401
|
+
end
|
402
|
+
|
403
|
+
if task.nil?
|
404
|
+
ui_status_text("Unrecognized object: #{object.class}")
|
405
|
+
else
|
406
|
+
task_apply_push(task)
|
316
407
|
end
|
317
408
|
when 'r'
|
318
|
-
|
319
|
-
|
409
|
+
ui_refresh_all
|
410
|
+
ui_status_text('')
|
320
411
|
when 'n'
|
321
|
-
task_name =
|
412
|
+
task_name = ui_status_input('New task: ')
|
322
413
|
if task_name.nil?
|
323
|
-
|
414
|
+
ui_status_text('Aborted.')
|
324
415
|
else
|
325
|
-
task_description =
|
416
|
+
task_description = ui_status_input('Description: ')
|
326
417
|
|
327
418
|
task = @stack.create(task_name, task_description)
|
328
|
-
|
329
|
-
@stack.pop_all(task)
|
330
|
-
@window_tasks.content_changed
|
419
|
+
task_apply_replace_stack(task)
|
331
420
|
|
332
|
-
|
333
|
-
|
334
|
-
stack_lines
|
335
|
-
window_refresh
|
421
|
+
ui_status_text("Task '#{task_name}' created: #{task.id}")
|
336
422
|
end
|
337
|
-
when 'p'
|
338
|
-
task = Task.new
|
339
|
-
task.name = "task #{Time.now.strftime(TIME_FORMAT)}"
|
340
|
-
task.description = 'description1'
|
341
|
-
|
342
|
-
@tasks[task.id] = task
|
343
|
-
@stack.push(task)
|
344
|
-
|
345
|
-
status_text("Task '#{task_name}' created: #{task.id}")
|
346
|
-
|
347
|
-
stack_lines
|
348
423
|
when 'x'
|
349
424
|
@stack.task.stop if @stack.has_task?
|
350
425
|
when 'c'
|
351
426
|
@stack.task.toggle if @stack.has_task?
|
352
427
|
when 'v'
|
353
428
|
if @stack.pop
|
354
|
-
|
355
|
-
|
429
|
+
window_content_changed
|
430
|
+
ui_refresh
|
356
431
|
end
|
432
|
+
when 'f'
|
433
|
+
task_apply_stack_pop_all
|
357
434
|
when 'h', '?'
|
358
|
-
|
435
|
+
ui_window_show(@window_help)
|
359
436
|
when 't' # Test Windows
|
360
|
-
|
437
|
+
ui_window_show(@window_test)
|
361
438
|
when '1'
|
362
|
-
|
439
|
+
ui_window_show(@window_timeline)
|
363
440
|
when '2'
|
364
|
-
|
441
|
+
ui_window_show(@window_tasks)
|
365
442
|
when 'w'
|
366
443
|
tasks_save
|
367
444
|
when 'q'
|
368
445
|
break
|
369
446
|
when nil
|
370
447
|
# Do some work.
|
371
|
-
|
448
|
+
ui_status_line
|
372
449
|
else
|
373
|
-
|
450
|
+
ui_status_text_error("Invalid key '#{key_pressed}' (#{Curses.keyname(key_pressed)})")
|
374
451
|
end
|
375
452
|
end
|
376
453
|
end
|
data/lib/timr/track.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
|
2
|
+
require 'time'
|
3
|
+
require 'thefox-ext'
|
4
|
+
|
5
|
+
module TheFox
|
6
|
+
module Timr
|
7
|
+
|
8
|
+
class Track
|
9
|
+
|
10
|
+
def initialize(task, tbegin = Time.now, tend = nil)
|
11
|
+
@task = task
|
12
|
+
@tbegin = tbegin
|
13
|
+
@tend = tend
|
14
|
+
end
|
15
|
+
|
16
|
+
def begin=(tb)
|
17
|
+
@tbegin = tb
|
18
|
+
end
|
19
|
+
|
20
|
+
def begin
|
21
|
+
@tbegin
|
22
|
+
end
|
23
|
+
|
24
|
+
def end=(te)
|
25
|
+
@tend = te
|
26
|
+
end
|
27
|
+
|
28
|
+
def end
|
29
|
+
@tend
|
30
|
+
end
|
31
|
+
|
32
|
+
def diff
|
33
|
+
if !@tbegin.nil? && !@tend.nil?
|
34
|
+
(@tend - @tbegin).abs
|
35
|
+
else
|
36
|
+
0
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def task
|
41
|
+
@task
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_h
|
45
|
+
h = {}
|
46
|
+
h['b'] = @tbegin.strftime(TIME_FORMAT) if !@tbegin.nil?
|
47
|
+
h['e'] = @tend.strftime(TIME_FORMAT) if !@tend.nil?
|
48
|
+
h
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
'track'
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_list_s
|
56
|
+
tend_date = nil
|
57
|
+
tend_time_s = ''
|
58
|
+
if !@tend.nil?
|
59
|
+
tend_time_s = !@tend.nil? ? @tend.strftime('%R') : 'xx:xx'
|
60
|
+
tend_date = @tend.to_date
|
61
|
+
end
|
62
|
+
|
63
|
+
tbegin_date_s = ''
|
64
|
+
tbegin_date = @tbegin.to_date
|
65
|
+
tend_date_s = ''
|
66
|
+
if (tbegin_date != tend_date && !tend_date.nil?) || !tbegin_date.today?
|
67
|
+
tbegin_date_s = @tbegin.strftime('%F')
|
68
|
+
tend_date_s = @tend.strftime('%F') if !@tend.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
'%10s %5s - %5s %10s %s' % [tbegin_date_s, @tbegin.strftime('%R'), tend_time_s, tend_date_s, @task.to_list_s]
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.from_h(task, h)
|
75
|
+
t = Track.new(task)
|
76
|
+
t.begin = Time.parse(h['b'])
|
77
|
+
t.end = Time.parse(h['e'])
|
78
|
+
t
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
data/lib/timr/version.rb
CHANGED
data/lib/timr/window.rb
CHANGED
@@ -8,15 +8,21 @@ module TheFox
|
|
8
8
|
@content_length = 0
|
9
9
|
@current_line = 0
|
10
10
|
@cursor = 1
|
11
|
+
@has_cursor = false
|
11
12
|
@content_changed = true
|
12
13
|
@content_refreshes = 1
|
13
|
-
@page =
|
14
|
+
@page = []
|
14
15
|
@page_changed = true
|
15
16
|
@page_refreshes = 1
|
16
17
|
|
18
|
+
setup
|
17
19
|
content_refresh
|
18
20
|
end
|
19
21
|
|
22
|
+
def setup
|
23
|
+
|
24
|
+
end
|
25
|
+
|
20
26
|
def content_length=(content_length)
|
21
27
|
@content_length = content_length
|
22
28
|
end
|
@@ -50,16 +56,13 @@ module TheFox
|
|
50
56
|
end
|
51
57
|
|
52
58
|
def page
|
53
|
-
if @
|
54
|
-
[]
|
55
|
-
|
56
|
-
|
57
|
-
@page = @content[@current_line, @content_length]
|
58
|
-
@page_refreshes += 1
|
59
|
-
@page_changed = false
|
60
|
-
end
|
61
|
-
@page
|
59
|
+
if @page_changed
|
60
|
+
@page = @content[@current_line, @content_length]
|
61
|
+
@page_refreshes += 1
|
62
|
+
@page_changed = false
|
62
63
|
end
|
64
|
+
|
65
|
+
@page
|
63
66
|
end
|
64
67
|
|
65
68
|
def page_object
|
@@ -67,7 +70,12 @@ module TheFox
|
|
67
70
|
end
|
68
71
|
|
69
72
|
def page_length
|
70
|
-
page
|
73
|
+
cpage = page
|
74
|
+
if cpage.nil?
|
75
|
+
0
|
76
|
+
else
|
77
|
+
cpage.length
|
78
|
+
end
|
71
79
|
end
|
72
80
|
|
73
81
|
def next_page?
|
@@ -97,10 +105,10 @@ module TheFox
|
|
97
105
|
@current_line > 0
|
98
106
|
end
|
99
107
|
|
100
|
-
def previous_page
|
108
|
+
def previous_page(length = @content_length)
|
101
109
|
if previous_page?
|
102
110
|
page_changed
|
103
|
-
@current_line -=
|
111
|
+
@current_line -= length
|
104
112
|
if @current_line < 0
|
105
113
|
@current_line = 0
|
106
114
|
end
|
@@ -118,8 +126,14 @@ module TheFox
|
|
118
126
|
end
|
119
127
|
|
120
128
|
def last_page
|
121
|
-
|
122
|
-
|
129
|
+
if !last_page?
|
130
|
+
page_changed
|
131
|
+
|
132
|
+
new_current_line = @content.length - @content_length
|
133
|
+
if new_current_line >= 0
|
134
|
+
@current_line = @content.length - @content_length
|
135
|
+
end
|
136
|
+
end
|
123
137
|
cursor_last_line
|
124
138
|
end
|
125
139
|
|
@@ -141,6 +155,10 @@ module TheFox
|
|
141
155
|
@cursor
|
142
156
|
end
|
143
157
|
|
158
|
+
def has_cursor?
|
159
|
+
@has_cursor
|
160
|
+
end
|
161
|
+
|
144
162
|
def cursor_next_line
|
145
163
|
@cursor += 1
|
146
164
|
border = @content_length - 2
|
@@ -183,6 +201,9 @@ module TheFox
|
|
183
201
|
|
184
202
|
def cursor_last_line
|
185
203
|
@cursor = @content_length
|
204
|
+
if page_length < @content_length
|
205
|
+
@cursor = page_length
|
206
|
+
end
|
186
207
|
end
|
187
208
|
|
188
209
|
def cursor_first_line
|
data/lib/timr/window_help.rb
CHANGED
@@ -12,12 +12,15 @@ module TheFox
|
|
12
12
|
' c .. Current Task: Start/Continue',
|
13
13
|
' x .. Current Task: Stop',
|
14
14
|
' v .. Current Task: Stop and Pop from Stack',
|
15
|
+
' f .. Stop and deselect all Tasks on the Stack',
|
16
|
+
' p, b .. Push and start selected Task.',
|
15
17
|
' r .. Refresh Window',
|
16
18
|
' w .. Write all changes.',
|
17
19
|
' q .. Exit',
|
18
20
|
' h .. Help',
|
19
21
|
' 1 .. Timeline Window',
|
20
22
|
' 2 .. Tasks Window',
|
23
|
+
' RETURN .. Start selected task.',
|
21
24
|
' KEY UP .. Move Cursor up.',
|
22
25
|
' KEY DOWN .. Move Cursor down.',
|
23
26
|
'',
|
data/lib/timr/window_tasks.rb
CHANGED
@@ -15,6 +15,7 @@ module TheFox
|
|
15
15
|
|
16
16
|
def content
|
17
17
|
if @tasks.nil? || @tasks.length == 0
|
18
|
+
@has_cursor = false
|
18
19
|
[
|
19
20
|
'',
|
20
21
|
'#### NO TASKS YET ####',
|
@@ -22,9 +23,10 @@ module TheFox
|
|
22
23
|
"Press 'n' to create a new task.",
|
23
24
|
]
|
24
25
|
else
|
26
|
+
@has_cursor = true
|
25
27
|
@tasks
|
26
28
|
.sort_by{ |k, v|
|
27
|
-
v.name
|
29
|
+
v.name.downcase
|
28
30
|
}
|
29
31
|
.map{ |a| a[1] }
|
30
32
|
end
|
data/lib/timr/window_test.rb
CHANGED
data/lib/timr/window_timeline.rb
CHANGED
@@ -4,8 +4,33 @@ module TheFox
|
|
4
4
|
|
5
5
|
class TimelineWindow < Window
|
6
6
|
|
7
|
+
@tasks = nil
|
8
|
+
|
9
|
+
def tasks=(tasks)
|
10
|
+
content_changed
|
11
|
+
@tasks = tasks
|
12
|
+
end
|
13
|
+
|
7
14
|
def content
|
8
|
-
|
15
|
+
if @tasks.nil? || @tasks.length == 0
|
16
|
+
@has_cursor = false
|
17
|
+
[
|
18
|
+
'',
|
19
|
+
'#### NO TASKS YET ####',
|
20
|
+
'',
|
21
|
+
"Press 'n' to create a new task.",
|
22
|
+
]
|
23
|
+
else
|
24
|
+
@has_cursor = true
|
25
|
+
@tasks
|
26
|
+
.map{ |task_id, task|
|
27
|
+
task.timeline
|
28
|
+
}
|
29
|
+
.flatten
|
30
|
+
.sort{ |task_a, task_b|
|
31
|
+
task_a.begin <=> task_b.begin || task_a.end <=> task_b.end
|
32
|
+
}
|
33
|
+
end
|
9
34
|
end
|
10
35
|
|
11
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.pre.dev.
|
4
|
+
version: 0.1.0.pre.dev.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Mayer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -80,12 +80,12 @@ files:
|
|
80
80
|
- Makefile
|
81
81
|
- Makefile.common
|
82
82
|
- README.md
|
83
|
-
- bin/dev
|
84
83
|
- bin/timr
|
85
84
|
- lib/timr.rb
|
86
85
|
- lib/timr/stack.rb
|
87
86
|
- lib/timr/task.rb
|
88
87
|
- lib/timr/timr.rb
|
88
|
+
- lib/timr/track.rb
|
89
89
|
- lib/timr/version.rb
|
90
90
|
- lib/timr/window.rb
|
91
91
|
- lib/timr/window_help.rb
|