timr 0.1.0 → 0.2.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.
- 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'
|