timr 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +1 -1
- data/.gitignore +2 -0
- data/Makefile +1 -1
- data/Makefile.common +3 -5
- data/bin/timr +14 -5
- data/lib/timr/stack.rb +15 -10
- data/lib/timr/task.rb +60 -11
- data/lib/timr/timr.rb +324 -117
- data/lib/timr/track.rb +75 -10
- data/lib/timr/version.rb +4 -4
- data/lib/timr/window.rb +29 -0
- data/lib/timr/window_help.rb +20 -18
- data/lib/timr/window_tasks.rb +6 -1
- data/lib/timr/window_timeline.rb +6 -1
- data/tests/tc_stack.rb +67 -45
- data/tests/tc_task.rb +55 -9
- data/tests/tc_track.rb +77 -40
- data/tests/tc_window.rb +309 -188
- metadata +2 -3
- data/Gemfile.lock +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e2d97ef6133107ff6c5f10ec8d7469ceab22317
|
4
|
+
data.tar.gz: 0eb7ce0ac1b3946fe7c4022c243cdfdd790eb360
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e431719fdaa4d85555c6578e61f80fb81c12e21d49b2ffbe74db47e2d21f727da133766b4eb645fbc04d77881586a35fe26febfc6d3a6ad03c95123f06b96421
|
7
|
+
data.tar.gz: f5fd40d36d15e55298686229bfd61e6dda2571bd8c0d4f306f89c7625ffcc53af52751f6ca6fb4ecfef7d241661c94a28af9d0de72ca7af024ed22327f8284e0
|
data/.editorconfig
CHANGED
data/.gitignore
CHANGED
data/Makefile
CHANGED
data/Makefile.common
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
|
2
2
|
# Ruby Common Big
|
3
|
-
# 2016-
|
3
|
+
# 2016-05-20
|
4
4
|
|
5
5
|
MV = mv -nv
|
6
|
-
RM = rm -
|
6
|
+
RM = rm -rfd
|
7
7
|
MKDIR = mkdir -p
|
8
8
|
CHMOD = chmod
|
9
9
|
BUNDLER = bundle
|
@@ -36,9 +36,7 @@ update:
|
|
36
36
|
|
37
37
|
.PHONY: clean
|
38
38
|
clean:
|
39
|
-
$(RM) .bundle
|
40
|
-
$(RM) .setup
|
41
|
-
$(RM) Gemfile.lock
|
39
|
+
$(RM) .bundle .setup Gemfile.lock
|
42
40
|
|
43
41
|
.PHONY: release
|
44
42
|
release: | releases
|
data/bin/timr
CHANGED
@@ -7,6 +7,7 @@ require 'timr'
|
|
7
7
|
|
8
8
|
@options = {
|
9
9
|
:dir => nil,
|
10
|
+
:config_path => "#{Dir.home}/.timr/timr.conf",
|
10
11
|
}
|
11
12
|
opts = OptionParser.new do |o|
|
12
13
|
o.banner = 'Usage: timr [options]'
|
@@ -16,11 +17,15 @@ opts = OptionParser.new do |o|
|
|
16
17
|
@options[:dir] = path
|
17
18
|
end
|
18
19
|
|
19
|
-
o.on('-p', '--project <name>', 'Project Name: use ~/.timr/NAME as path.') do |name|
|
20
|
+
o.on('-p', '--project <name>', 'Project Name: use ~/.timr/projects/NAME as path.') do |name|
|
20
21
|
@options[:dir] = File.expand_path(name, "#{Dir.home}/.timr/projects")
|
21
22
|
end
|
22
23
|
|
23
|
-
o.
|
24
|
+
o.on('-c', '--config <path>', 'Path to config file. Default: ~/.timr/timr.conf') do |path|
|
25
|
+
@options[:config_path] = File.expand_path(path)
|
26
|
+
end
|
27
|
+
|
28
|
+
o.on_tail('-V', '--version', 'Show version.') do
|
24
29
|
puts "#{TheFox::Timr::NAME} #{TheFox::Timr::VERSION} (#{TheFox::Timr::DATE})"
|
25
30
|
puts "#{TheFox::Timr::HOMEPAGE}"
|
26
31
|
exit
|
@@ -35,6 +40,10 @@ end
|
|
35
40
|
ARGV << '-h' if ARGV.count == 0
|
36
41
|
opts.parse(ARGV)
|
37
42
|
|
38
|
-
timr = TheFox::Timr::Timr.new(@options[:dir])
|
39
|
-
|
40
|
-
timr.
|
43
|
+
timr = TheFox::Timr::Timr.new(@options[:dir], @options[:config_path])
|
44
|
+
begin
|
45
|
+
timr.run
|
46
|
+
rescue Exception => e
|
47
|
+
timr.close
|
48
|
+
raise e
|
49
|
+
end
|
data/lib/timr/stack.rb
CHANGED
@@ -17,7 +17,7 @@ module TheFox
|
|
17
17
|
!@task.nil?
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def size
|
21
21
|
@tasks.length
|
22
22
|
end
|
23
23
|
|
@@ -34,15 +34,22 @@ module TheFox
|
|
34
34
|
if !old.nil?
|
35
35
|
old.stop
|
36
36
|
@task = @tasks.last
|
37
|
-
@task.start if
|
37
|
+
@task.start if !@task.nil?
|
38
38
|
true
|
39
39
|
else
|
40
40
|
false
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
def pop_all(new_task = nil)
|
45
|
-
if @task
|
44
|
+
def pop_all(new_task = nil, parent_track = nil)
|
45
|
+
if @task == new_task
|
46
|
+
#puts 'tasks =='
|
47
|
+
x = @task.start(parent_track)
|
48
|
+
#puts "return #{x}"
|
49
|
+
#puts
|
50
|
+
x
|
51
|
+
else
|
52
|
+
#puts 'stop all tasks'
|
46
53
|
@tasks.each do |task|
|
47
54
|
task.stop
|
48
55
|
end
|
@@ -50,20 +57,18 @@ module TheFox
|
|
50
57
|
@task = nil
|
51
58
|
|
52
59
|
if !new_task.nil?
|
53
|
-
push(new_task)
|
60
|
+
push(new_task, parent_track)
|
54
61
|
end
|
55
62
|
true
|
56
|
-
else
|
57
|
-
false
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
61
|
-
def push(task)
|
66
|
+
def push(task, parent_track = nil)
|
62
67
|
if !@tasks.include?(task)
|
63
|
-
@task.
|
68
|
+
@task.pause if has_task?
|
64
69
|
|
65
70
|
@task = task
|
66
|
-
@task.start
|
71
|
+
@task.start(parent_track)
|
67
72
|
@tasks << @task
|
68
73
|
true
|
69
74
|
else
|
data/lib/timr/task.rb
CHANGED
@@ -19,8 +19,8 @@ module TheFox
|
|
19
19
|
'id' => UUID.new.generate,
|
20
20
|
'name' => nil,
|
21
21
|
'description' => nil,
|
22
|
-
'created' => Time.now.utc.strftime(
|
23
|
-
'modified' => Time.now.utc.strftime(
|
22
|
+
'created' => Time.now.utc.strftime(TIME_FORMAT_FILE),
|
23
|
+
'modified' => Time.now.utc.strftime(TIME_FORMAT_FILE),
|
24
24
|
}
|
25
25
|
@track = nil
|
26
26
|
@timeline = []
|
@@ -48,7 +48,7 @@ module TheFox
|
|
48
48
|
timeline_c = @timeline
|
49
49
|
.map{ |track|
|
50
50
|
h = track.to_h
|
51
|
-
h['e'] = Time.now.utc.strftime(
|
51
|
+
h['e'] = Time.now.utc.strftime(TIME_FORMAT_FILE) if !h.has_key?('e') || h['e'].nil?
|
52
52
|
h
|
53
53
|
}
|
54
54
|
|
@@ -67,10 +67,16 @@ module TheFox
|
|
67
67
|
@status == :running
|
68
68
|
end
|
69
69
|
|
70
|
+
def paused?
|
71
|
+
@status == :paused
|
72
|
+
end
|
73
|
+
|
70
74
|
def status
|
71
75
|
case @status
|
72
76
|
when :running
|
73
77
|
?>
|
78
|
+
when :paused
|
79
|
+
?#
|
74
80
|
when :stop
|
75
81
|
?|
|
76
82
|
end
|
@@ -78,7 +84,7 @@ module TheFox
|
|
78
84
|
|
79
85
|
def changed
|
80
86
|
@changed = true
|
81
|
-
@meta['modified'] = Time.now.utc.strftime(
|
87
|
+
@meta['modified'] = Time.now.utc.strftime(TIME_FORMAT_FILE)
|
82
88
|
end
|
83
89
|
|
84
90
|
def id
|
@@ -115,22 +121,61 @@ module TheFox
|
|
115
121
|
@timeline
|
116
122
|
end
|
117
123
|
|
118
|
-
def start
|
119
|
-
|
120
|
-
|
121
|
-
|
124
|
+
def start(parent_track = nil)
|
125
|
+
create_new_track = false
|
126
|
+
|
127
|
+
if running?
|
128
|
+
if !parent_track.nil?
|
129
|
+
if @track.description != parent_track.description
|
130
|
+
stop
|
131
|
+
create_new_track = true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
elsif paused?
|
135
|
+
parent_track = @track
|
136
|
+
create_new_track = true
|
137
|
+
else
|
138
|
+
create_new_track = true
|
139
|
+
end
|
140
|
+
|
141
|
+
if create_new_track
|
142
|
+
@track = Track.new
|
143
|
+
if !parent_track.nil?
|
144
|
+
@track.parent = parent_track
|
145
|
+
@track.description = parent_track.description
|
146
|
+
end
|
147
|
+
|
148
|
+
@track.task = self
|
149
|
+
@track.begin_time = Time.now
|
122
150
|
@timeline << @track
|
151
|
+
|
152
|
+
@changed = true
|
123
153
|
end
|
154
|
+
|
124
155
|
@status = :running
|
156
|
+
|
157
|
+
create_new_track
|
125
158
|
end
|
126
159
|
|
127
|
-
def
|
128
|
-
if
|
160
|
+
def pause
|
161
|
+
if !@track.nil?
|
162
|
+
@status = :paused
|
129
163
|
@changed = true
|
130
164
|
@track.end_time = Time.now
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def stop
|
169
|
+
if !@track.nil?
|
170
|
+
if running?
|
171
|
+
@changed = true
|
172
|
+
@track.end_time = Time.now
|
173
|
+
end
|
174
|
+
|
131
175
|
@track = nil
|
132
176
|
@timeline_diff_total = nil
|
133
177
|
end
|
178
|
+
|
134
179
|
@status = :stop
|
135
180
|
end
|
136
181
|
|
@@ -143,7 +188,11 @@ module TheFox
|
|
143
188
|
end
|
144
189
|
|
145
190
|
def to_s
|
146
|
-
|
191
|
+
track_description = ''
|
192
|
+
if has_track? && !@track.description.nil? && @track.description.to_s.length > 0
|
193
|
+
track_description = ": #{@track.description}"
|
194
|
+
end
|
195
|
+
'%s%s' % [name, track_description]
|
147
196
|
end
|
148
197
|
|
149
198
|
def to_list_s
|
data/lib/timr/timr.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
require 'curses'
|
3
3
|
require 'time'
|
4
4
|
require 'fileutils'
|
5
|
+
require 'yaml/store'
|
6
|
+
require 'thefox-ext'
|
5
7
|
|
6
8
|
module TheFox
|
7
9
|
module Timr
|
@@ -10,19 +12,31 @@ module TheFox
|
|
10
12
|
|
11
13
|
#include Curses
|
12
14
|
|
13
|
-
def initialize(
|
14
|
-
@base_dir_path = File.expand_path(
|
15
|
+
def initialize(base_dir_path, config_path = nil)
|
16
|
+
@base_dir_path = File.expand_path(base_dir_path)
|
15
17
|
@base_dir_name = File.basename(@base_dir_path)
|
16
18
|
@data_dir_path = "#{@base_dir_path}/data"
|
19
|
+
@config_path = config_path
|
17
20
|
|
18
|
-
puts "base:
|
19
|
-
puts "name:
|
20
|
-
puts "data:
|
21
|
+
puts "base: #{@base_dir_path}"
|
22
|
+
puts "name: #{@base_dir_name}"
|
23
|
+
puts "data: #{@data_dir_path}"
|
24
|
+
puts "config: #{@config_path}"
|
21
25
|
|
22
26
|
@stack = Stack.new
|
23
27
|
@tasks = {}
|
24
28
|
@last_write = nil
|
29
|
+
@config = {
|
30
|
+
'clock' => {
|
31
|
+
'default' => '%F %R',
|
32
|
+
'large' => '%F %T',
|
33
|
+
'short' => '%R',
|
34
|
+
},
|
35
|
+
}
|
36
|
+
#@ui_window_refresh_last = nil
|
37
|
+
#@ui_status_line_last = nil
|
25
38
|
|
39
|
+
config_read
|
26
40
|
init_dirs
|
27
41
|
tasks_load
|
28
42
|
|
@@ -37,6 +51,15 @@ module TheFox
|
|
37
51
|
@window_timeline.tasks = @tasks
|
38
52
|
end
|
39
53
|
|
54
|
+
def config_read(path = @config_path)
|
55
|
+
if !path.nil? && File.exist?(path)
|
56
|
+
content = YAML::load_file(path)
|
57
|
+
if content
|
58
|
+
@config.merge_recursive!(content)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
40
63
|
def init_dirs
|
41
64
|
if !Dir.exist?(@base_dir_path)
|
42
65
|
FileUtils.mkdir_p(@base_dir_path)
|
@@ -108,14 +131,17 @@ module TheFox
|
|
108
131
|
end
|
109
132
|
end
|
110
133
|
|
111
|
-
|
134
|
+
# This is the line on the bottom of the screen.
|
135
|
+
def ui_status_text(text = nil, attrn = Curses::A_NORMAL)
|
112
136
|
line_nr = Curses.lines - 1
|
113
137
|
|
114
138
|
Curses.setpos(line_nr, 0)
|
115
139
|
Curses.clrtoeol
|
116
|
-
|
117
|
-
|
118
|
-
Curses.
|
140
|
+
if !text.nil?
|
141
|
+
Curses.setpos(line_nr, COL)
|
142
|
+
Curses.attron(attrn) do
|
143
|
+
Curses.addstr(text)
|
144
|
+
end
|
119
145
|
end
|
120
146
|
Curses.refresh
|
121
147
|
end
|
@@ -124,6 +150,7 @@ module TheFox
|
|
124
150
|
ui_status_text(text, Curses.color_pair(Curses::COLOR_RED) | Curses::A_BOLD)
|
125
151
|
end
|
126
152
|
|
153
|
+
# Use the Status Text line to get an input from user.
|
127
154
|
def ui_status_input(text)
|
128
155
|
Curses.echo
|
129
156
|
Curses.timeout = -1
|
@@ -140,12 +167,17 @@ module TheFox
|
|
140
167
|
abort = true
|
141
168
|
break
|
142
169
|
when Curses::Key::BACKSPACE
|
143
|
-
|
144
|
-
|
170
|
+
if input.length > 0
|
171
|
+
Curses.stdscr.delch
|
172
|
+
input = input[0..-2]
|
173
|
+
end
|
145
174
|
when 10
|
146
175
|
break
|
176
|
+
when nil
|
177
|
+
# Do nothing.
|
178
|
+
#sleep TIMEOUT.to_f / 1000
|
147
179
|
else
|
148
|
-
input += key_pressed
|
180
|
+
input += key_pressed.to_s
|
149
181
|
end
|
150
182
|
end
|
151
183
|
if abort
|
@@ -159,9 +191,75 @@ module TheFox
|
|
159
191
|
input
|
160
192
|
end
|
161
193
|
|
194
|
+
# The second line from the bottom:
|
195
|
+
# Show current Track status, Track Time Difference, Task Time Total.
|
162
196
|
def ui_status_line(init = false)
|
163
197
|
line_nr = Curses.lines - 2
|
164
198
|
|
199
|
+
status_s = ''
|
200
|
+
track_begin_time_s = ''
|
201
|
+
|
202
|
+
run_time_track_str = ''
|
203
|
+
run_time_track_h = 0
|
204
|
+
run_time_track_m = 0
|
205
|
+
run_time_track_s = 0
|
206
|
+
|
207
|
+
run_time_total_str = ''
|
208
|
+
run_time_total_h = 0
|
209
|
+
run_time_total_m = 0
|
210
|
+
run_time_total_s = 0
|
211
|
+
|
212
|
+
time_s = ''
|
213
|
+
|
214
|
+
stack_has_task = @stack.has_task?.freeze
|
215
|
+
if stack_has_task
|
216
|
+
status_s = @stack.task.status
|
217
|
+
|
218
|
+
track_begin_time_s = '--:--'
|
219
|
+
if @stack.task.has_track?
|
220
|
+
track_begin_time_s = @stack.task.track.begin_time.strftime('%R')
|
221
|
+
end
|
222
|
+
|
223
|
+
run_time_track_h, run_time_track_m, run_time_track_s = @stack.task.run_time_track
|
224
|
+
run_time_total_h, run_time_total_m, run_time_total_s = @stack.task.run_time_total
|
225
|
+
else
|
226
|
+
status_s = TASK_NO_TASK_LOADED_CHAR
|
227
|
+
end
|
228
|
+
|
229
|
+
if Curses.cols > MIN_COLS
|
230
|
+
if stack_has_task
|
231
|
+
run_time_track_str = '%2d:%02d:%02d' % [run_time_track_h, run_time_track_m, run_time_track_s]
|
232
|
+
run_time_total_str = '%2d:%02d:%02d' % [run_time_total_h, run_time_total_m, run_time_total_s]
|
233
|
+
end
|
234
|
+
|
235
|
+
time_format = @config['clock']['default']
|
236
|
+
if Curses.cols <= 50
|
237
|
+
if stack_has_task
|
238
|
+
run_time_track_str = '%2d:%02d' % [run_time_track_h, run_time_track_m]
|
239
|
+
end
|
240
|
+
run_time_total_str = ''
|
241
|
+
|
242
|
+
time_format = nil
|
243
|
+
elsif Curses.cols <= 60
|
244
|
+
if stack_has_task
|
245
|
+
run_time_track_str = '%2d:%02d' % [run_time_track_h, run_time_track_m]
|
246
|
+
run_time_total_str = '%2d:%02d' % [run_time_total_h, run_time_total_m]
|
247
|
+
end
|
248
|
+
|
249
|
+
time_format = @config['clock']['short']
|
250
|
+
elsif Curses.cols > 80
|
251
|
+
time_format = @config['clock']['large']
|
252
|
+
end
|
253
|
+
if !time_format.nil?
|
254
|
+
time_s = Time.now.strftime(time_format)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
line = "#{status_s} #{track_begin_time_s} #{run_time_track_str} #{run_time_total_str}"
|
259
|
+
|
260
|
+
rest = Curses.cols - COL - line.length - time_s.length - 1
|
261
|
+
line += ' ' * rest + time_s
|
262
|
+
|
165
263
|
Curses.attron(Curses.color_pair(Curses::COLOR_GREEN) | Curses::A_NORMAL) do
|
166
264
|
if init
|
167
265
|
Curses.setpos(line_nr, 0)
|
@@ -170,37 +268,7 @@ module TheFox
|
|
170
268
|
end
|
171
269
|
|
172
270
|
Curses.setpos(line_nr, COL)
|
173
|
-
|
174
|
-
status = @stack.task.status
|
175
|
-
track_begin_time_s = '--:--'
|
176
|
-
if @stack.task.has_track?
|
177
|
-
track_begin_time_s = @stack.task.track.begin_time.strftime('%R')
|
178
|
-
end
|
179
|
-
run_time_track = '%4d:%02d:%02d' % @stack.task.run_time_track
|
180
|
-
run_time_total = '%4d:%02d:%02d' % @stack.task.run_time_total
|
181
|
-
|
182
|
-
Curses.addstr("#{status} #{track_begin_time_s} #{run_time_track} #{run_time_total}")
|
183
|
-
else
|
184
|
-
Curses.addstr("#{TASK_NO_TASK_LOADED_C} --:-- ----:--:-- ----:--:--")
|
185
|
-
end
|
186
|
-
|
187
|
-
if Curses.cols > MIN_COLS
|
188
|
-
time_format = '%F %R'
|
189
|
-
if Curses.cols <= 30
|
190
|
-
time_format = '%R'
|
191
|
-
elsif Curses.cols <= 40
|
192
|
-
time_format = '%m-%d %R'
|
193
|
-
elsif Curses.cols <= 50
|
194
|
-
time_format = '%y-%m-%d %R'
|
195
|
-
elsif Curses.cols <= 60
|
196
|
-
time_format = '%F %R'
|
197
|
-
elsif Curses.cols > 80
|
198
|
-
time_format = '%F %T'
|
199
|
-
end
|
200
|
-
time_str = Time.now.strftime(time_format)
|
201
|
-
Curses.setpos(line_nr, Curses.cols - time_str.length - 1)
|
202
|
-
Curses.addstr(time_str)
|
203
|
-
end
|
271
|
+
Curses.addstr(line)
|
204
272
|
end
|
205
273
|
|
206
274
|
Curses.refresh
|
@@ -208,18 +276,47 @@ module TheFox
|
|
208
276
|
|
209
277
|
def ui_window_show(window)
|
210
278
|
@window = window
|
211
|
-
|
279
|
+
ui_window_refresh_all
|
212
280
|
end
|
213
281
|
|
214
|
-
def
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
282
|
+
def ui_content_line(line_nr, text)
|
283
|
+
Curses.setpos(line_nr, 0)
|
284
|
+
Curses.clrtoeol
|
285
|
+
|
286
|
+
rest = Curses.cols - text.length - COL
|
287
|
+
if rest < 0
|
288
|
+
rest = 0
|
219
289
|
end
|
290
|
+
out = ' ' * COL + text + ' ' * rest
|
220
291
|
|
292
|
+
if @window.has_cursor? && line_nr == @window.cursor
|
293
|
+
Curses.attron(Curses.color_pair(Curses::COLOR_BLUE) | Curses::A_BOLD) do
|
294
|
+
Curses.addstr(out)
|
295
|
+
end
|
296
|
+
else
|
297
|
+
Curses.addstr(out)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def ui_window_refresh(lines)
|
302
|
+
ui_window_refresh_all
|
303
|
+
|
304
|
+
# if !@window.nil?
|
305
|
+
# simple_refresh = @window.cursor_on_inner_range?
|
306
|
+
|
307
|
+
# if !simple_refresh || simple_refresh != @ui_window_refresh_last
|
308
|
+
# ui_window_refresh_all
|
309
|
+
# else
|
310
|
+
# ui_window_refresh_simple(lines)
|
311
|
+
# end
|
312
|
+
|
313
|
+
# @ui_window_refresh_last = simple_refresh
|
314
|
+
# end
|
315
|
+
end
|
316
|
+
|
317
|
+
def ui_window_refresh_all
|
221
318
|
if !@window.nil?
|
222
|
-
|
319
|
+
content_line_nr = 1
|
223
320
|
@window.content_refresh
|
224
321
|
max_line_len = Curses.cols - 2
|
225
322
|
@window.page.each do |line_object|
|
@@ -231,36 +328,81 @@ module TheFox
|
|
231
328
|
end
|
232
329
|
|
233
330
|
if line_text.length > max_line_len
|
234
|
-
|
235
|
-
line_text = "#{line_text[
|
331
|
+
range = 0..-(line_text.length - max_line_len + 4)
|
332
|
+
line_text = "#{line_text[range]}..."
|
236
333
|
end
|
237
334
|
|
238
|
-
|
335
|
+
ui_content_line(content_line_nr, line_text)
|
239
336
|
|
240
|
-
|
241
|
-
if line_nr == @window.cursor
|
242
|
-
Curses.setpos(line_nr, 0)
|
243
|
-
Curses.attron(Curses.color_pair(Curses::COLOR_BLUE) | Curses::A_BOLD) do
|
244
|
-
Curses.addstr(' ' * COL + line_text + ' ' * rest)
|
245
|
-
end
|
246
|
-
else
|
247
|
-
Curses.setpos(line_nr, COL)
|
248
|
-
Curses.addstr(line_text)
|
249
|
-
end
|
250
|
-
else
|
251
|
-
Curses.setpos(line_nr, COL)
|
252
|
-
Curses.addstr(line_text)
|
253
|
-
end
|
337
|
+
content_line_nr += 1
|
254
338
|
|
255
|
-
|
339
|
+
# if $DEBUG
|
340
|
+
# Curses.refresh
|
341
|
+
# sleep 0.01
|
342
|
+
# end
|
343
|
+
end
|
344
|
+
|
345
|
+
window_page_length = @window.page_length
|
346
|
+
content_length = ui_content_length
|
347
|
+
if window_page_length < content_length
|
348
|
+
((window_page_length + 1)..content_length).to_a.each do |rest_line_nr|
|
349
|
+
Curses.setpos(rest_line_nr, 0)
|
350
|
+
Curses.clrtoeol
|
351
|
+
|
352
|
+
# if $DEBUG
|
353
|
+
# Curses.addstr("-- CLEAR -- #{rest_line_nr} #{Time.now.strftime('%T')}")
|
354
|
+
# Curses.refresh
|
355
|
+
# sleep 0.01
|
356
|
+
# end
|
357
|
+
end
|
256
358
|
end
|
257
359
|
end
|
258
360
|
|
259
361
|
Curses.refresh
|
260
362
|
end
|
261
363
|
|
364
|
+
def ui_window_refresh_simple(lines)
|
365
|
+
max_line_len = Curses.cols - 2
|
366
|
+
|
367
|
+
|
368
|
+
old_cursor = @window.cursor + (lines * -1)
|
369
|
+
old_line_object = @window.page[old_cursor - 1]
|
370
|
+
|
371
|
+
old_line_text = ''
|
372
|
+
if old_line_object.is_a?(Task) || old_line_object.is_a?(Track)
|
373
|
+
old_line_text = old_line_object.to_list_s
|
374
|
+
else
|
375
|
+
old_line_text = old_line_object.to_s
|
376
|
+
end
|
377
|
+
|
378
|
+
if old_line_text.length > max_line_len
|
379
|
+
range = 0..-(line_text.length - max_line_len + 4)
|
380
|
+
old_line_text = "#{old_line_text[range]}..."
|
381
|
+
end
|
382
|
+
|
383
|
+
|
384
|
+
new_cursor = @window.cursor
|
385
|
+
new_line_object = @window.page[new_cursor - 1]
|
386
|
+
|
387
|
+
new_line_text = ''
|
388
|
+
if new_line_object.is_a?(Task) || new_line_object.is_a?(Track)
|
389
|
+
new_line_text = new_line_object.to_list_s
|
390
|
+
else
|
391
|
+
new_line_text = new_line_object.to_s
|
392
|
+
end
|
393
|
+
|
394
|
+
if new_line_text.length > max_line_len
|
395
|
+
range = 0..-(line_text.length - max_line_len + 4)
|
396
|
+
new_line_text = "#{new_line_text[range]}..."
|
397
|
+
end
|
398
|
+
|
399
|
+
ui_content_line(old_cursor, old_line_text)
|
400
|
+
ui_content_line(@window.cursor, new_line_text)
|
401
|
+
Curses.refresh
|
402
|
+
end
|
403
|
+
|
262
404
|
def ui_content_length
|
263
|
-
Curses.lines - RESERVED_LINES - @stack.
|
405
|
+
Curses.lines - RESERVED_LINES - @stack.size
|
264
406
|
end
|
265
407
|
|
266
408
|
def update_content_length
|
@@ -272,20 +414,22 @@ module TheFox
|
|
272
414
|
@window_timeline.content_length = cl
|
273
415
|
end
|
274
416
|
|
275
|
-
def
|
417
|
+
def ui_refresh_simple
|
276
418
|
ui_stack_lines_refresh
|
277
|
-
|
419
|
+
ui_window_refresh_all
|
278
420
|
end
|
279
421
|
|
280
422
|
def ui_refresh_all
|
423
|
+
#@ui_window_refresh_last = nil
|
424
|
+
|
281
425
|
update_content_length
|
282
426
|
ui_title_line
|
283
427
|
ui_status_line(true)
|
284
|
-
|
428
|
+
ui_refresh_simple
|
285
429
|
end
|
286
430
|
|
287
431
|
def ui_stack_lines_refresh
|
288
|
-
line_nr = Curses.lines - (3 + (@stack.
|
432
|
+
line_nr = Curses.lines - (3 + (@stack.size - 1))
|
289
433
|
|
290
434
|
Curses.attron(Curses.color_pair(Curses::COLOR_BLUE)) do
|
291
435
|
@stack.tasks_texts.reverse.each do |line_text|
|
@@ -302,41 +446,42 @@ module TheFox
|
|
302
446
|
Curses.refresh
|
303
447
|
end
|
304
448
|
|
305
|
-
def task_apply(task = nil, push = false)
|
449
|
+
def task_apply(task = nil, parent_track = nil, push = false)
|
306
450
|
if task.nil?
|
307
451
|
@stack.pop_all
|
308
452
|
else
|
309
453
|
@tasks[task.id] = task
|
310
454
|
if push
|
311
|
-
@stack.push(task)
|
455
|
+
@stack.push(task, parent_track)
|
312
456
|
else
|
313
|
-
@stack.pop_all(task)
|
457
|
+
@stack.pop_all(task, parent_track)
|
314
458
|
end
|
315
459
|
end
|
316
460
|
|
317
461
|
update_content_length
|
318
462
|
window_content_changed
|
319
463
|
ui_stack_lines_refresh
|
320
|
-
|
464
|
+
ui_window_refresh_all
|
321
465
|
end
|
322
466
|
|
323
|
-
def task_apply_replace_stack(task)
|
324
|
-
|
467
|
+
def task_apply_replace_stack(task, parent_track = nil)
|
468
|
+
if !task.nil?
|
469
|
+
task_apply(task, parent_track, false)
|
470
|
+
end
|
325
471
|
end
|
326
472
|
|
327
473
|
def task_apply_stack_pop_all
|
328
|
-
task_apply(nil, false)
|
474
|
+
task_apply(nil, nil, false)
|
329
475
|
end
|
330
476
|
|
331
|
-
def task_apply_push(task)
|
332
|
-
task_apply(task, true)
|
477
|
+
def task_apply_push(task, parent_track = nil)
|
478
|
+
task_apply(task, parent_track, true)
|
333
479
|
end
|
334
480
|
|
335
481
|
def task_apply_pop
|
336
482
|
if @stack.pop
|
337
483
|
update_content_length
|
338
|
-
|
339
|
-
ui_refresh
|
484
|
+
ui_refresh_simple
|
340
485
|
end
|
341
486
|
end
|
342
487
|
|
@@ -350,6 +495,21 @@ module TheFox
|
|
350
495
|
@window_timeline.content_changed
|
351
496
|
end
|
352
497
|
|
498
|
+
def window_page_object
|
499
|
+
object = @window.page_object if !@window.nil?
|
500
|
+
|
501
|
+
task = nil
|
502
|
+
track = nil
|
503
|
+
if object.is_a?(Task)
|
504
|
+
task = object
|
505
|
+
elsif object.is_a?(Track)
|
506
|
+
task = object.task
|
507
|
+
track = object
|
508
|
+
end
|
509
|
+
|
510
|
+
[task, track]
|
511
|
+
end
|
512
|
+
|
353
513
|
def write_all_data
|
354
514
|
if @last_write.nil?
|
355
515
|
@last_write = Time.now
|
@@ -373,32 +533,64 @@ module TheFox
|
|
373
533
|
case key_pressed
|
374
534
|
when Curses::Key::NPAGE
|
375
535
|
@window.next_page if !@window.nil?
|
376
|
-
|
536
|
+
|
537
|
+
# if $DEBUG
|
538
|
+
# ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes])
|
539
|
+
# end
|
540
|
+
|
541
|
+
ui_window_refresh_all
|
377
542
|
when Curses::Key::PPAGE
|
378
543
|
@window.previous_page if !@window.nil?
|
379
|
-
|
544
|
+
|
545
|
+
# if $DEBUG
|
546
|
+
# ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes])
|
547
|
+
# end
|
548
|
+
|
549
|
+
ui_window_refresh_all
|
380
550
|
when Curses::Key::DOWN
|
381
551
|
if !@window.nil? && @window.has_cursor?
|
382
|
-
@window.
|
552
|
+
simple_refresh_b = @window.cursor_on_inner_range?
|
383
553
|
|
384
|
-
|
554
|
+
@window.cursor_next_line
|
385
555
|
|
386
|
-
|
556
|
+
simple_refresh_a = @window.cursor_on_inner_range?
|
557
|
+
|
558
|
+
# if $DEBUG
|
559
|
+
# ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d %02d %02d %s %s' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes, @window.cursor_border_top, @window.cursor_border_bottom, simple_refresh_b ? 'SIMPLE' : 'FULL', simple_refresh_a ? 'SIMPLE' : 'FULL'])
|
560
|
+
#end
|
561
|
+
|
562
|
+
ui_window_refresh(1)
|
387
563
|
end
|
388
564
|
when Curses::Key::UP
|
389
565
|
if !@window.nil? && @window.has_cursor?
|
566
|
+
simple_refresh_b = @window.cursor_on_inner_range?
|
567
|
+
|
390
568
|
@window.cursor_previous_line
|
391
569
|
|
392
|
-
|
570
|
+
simple_refresh_a = @window.cursor_on_inner_range?
|
571
|
+
|
572
|
+
# if $DEBUG
|
573
|
+
# ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d %02d %02d %s %s' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes, @window.cursor_border_top, @window.cursor_border_bottom, simple_refresh_b ? 'SIMPLE' : 'FULL', simple_refresh_a ? 'SIMPLE' : 'FULL'])
|
574
|
+
# end
|
393
575
|
|
394
|
-
ui_window_refresh
|
576
|
+
ui_window_refresh(-1)
|
395
577
|
end
|
396
578
|
when Curses::Key::HOME
|
397
579
|
@window.first_page if !@window.nil?
|
398
|
-
|
580
|
+
|
581
|
+
if $DEBUG
|
582
|
+
ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes])
|
583
|
+
end
|
584
|
+
|
585
|
+
ui_window_refresh_all
|
399
586
|
when Curses::Key::END
|
400
587
|
@window.last_page if !@window.nil?
|
401
|
-
|
588
|
+
|
589
|
+
# if $DEBUG
|
590
|
+
# ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes])
|
591
|
+
# end
|
592
|
+
|
593
|
+
ui_window_refresh_all
|
402
594
|
when Curses::Key::RESIZE
|
403
595
|
update_content_length
|
404
596
|
ui_status_text("Window size: #{Curses.cols}x#{Curses.lines}")
|
@@ -408,36 +600,31 @@ module TheFox
|
|
408
600
|
# comment this line.
|
409
601
|
ui_refresh_all
|
410
602
|
when 10
|
411
|
-
|
603
|
+
task, track = window_page_object
|
604
|
+
task_apply_replace_stack(task, track)
|
605
|
+
when '#'
|
606
|
+
task, * = window_page_object
|
412
607
|
|
413
|
-
|
414
|
-
|
415
|
-
task = object
|
416
|
-
elsif object.is_a?(Track)
|
417
|
-
task = object.task
|
418
|
-
end
|
608
|
+
track_description = ui_status_input('Track Description: ')
|
609
|
+
ui_status_text("Description: '#{track_description}'")
|
419
610
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
when 'b', 'p'
|
424
|
-
object = @window.page_object if !@window.nil?
|
611
|
+
track = Track.new
|
612
|
+
track.task = task
|
613
|
+
track.description = track_description
|
425
614
|
|
426
|
-
task
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
task = object.task
|
431
|
-
end
|
615
|
+
task_apply_replace_stack(task, track)
|
616
|
+
#ui_status_text('OK')
|
617
|
+
when 'b', 'p'
|
618
|
+
task, track = window_page_object
|
432
619
|
|
433
620
|
if task.nil?
|
434
621
|
ui_status_text("Unrecognized object: #{object.class}")
|
435
622
|
else
|
436
|
-
task_apply_push(task)
|
623
|
+
task_apply_push(task, track)
|
437
624
|
end
|
438
625
|
when 'r'
|
439
626
|
ui_refresh_all
|
440
|
-
ui_status_text
|
627
|
+
ui_status_text
|
441
628
|
when 'n'
|
442
629
|
task_name = ui_status_input('New task: ')
|
443
630
|
if task_name.nil?
|
@@ -445,30 +632,50 @@ module TheFox
|
|
445
632
|
else
|
446
633
|
task = Task.new
|
447
634
|
task.name = task_name
|
635
|
+
task.save_to_file(@data_dir_path)
|
636
|
+
|
448
637
|
task_apply_replace_stack(task)
|
449
638
|
|
639
|
+
ui_status_text("Task '#{task_name}' created.")
|
640
|
+
end
|
641
|
+
when 't'
|
642
|
+
task_name = ui_status_input('New task: ')
|
643
|
+
if task_name.nil?
|
644
|
+
ui_status_text('Aborted.')
|
645
|
+
else
|
646
|
+
task = Task.new
|
647
|
+
task.name = task_name
|
648
|
+
task.save_to_file(@data_dir_path)
|
649
|
+
|
650
|
+
@tasks[task.id] = task
|
651
|
+
|
652
|
+
update_content_length
|
653
|
+
window_content_changed
|
654
|
+
ui_stack_lines_refresh
|
655
|
+
ui_window_refresh_all
|
656
|
+
|
450
657
|
ui_status_text("Task '#{task_name}' created.")
|
451
658
|
end
|
452
659
|
when 'x'
|
453
660
|
@stack.task.stop if @stack.has_task?
|
454
661
|
window_content_changed
|
455
|
-
|
662
|
+
ui_refresh_simple
|
456
663
|
when 'c'
|
457
664
|
@stack.task.toggle if @stack.has_task?
|
458
665
|
window_content_changed
|
459
|
-
|
666
|
+
ui_refresh_simple
|
460
667
|
when 'v'
|
461
668
|
task_apply_pop
|
462
669
|
when 'f'
|
463
670
|
task_apply_stack_pop_all
|
464
671
|
when 'h', '?'
|
465
672
|
ui_window_show(@window_help)
|
466
|
-
when 't' # Test Windows
|
467
|
-
ui_window_show(@window_test)
|
468
673
|
when '1'
|
469
674
|
ui_window_show(@window_timeline)
|
470
675
|
when '2'
|
471
676
|
ui_window_show(@window_tasks)
|
677
|
+
when '3' # Test Windows
|
678
|
+
ui_window_show(@window_test)
|
472
679
|
when 'w'
|
473
680
|
tasks_save(true)
|
474
681
|
when 'q'
|