working_set 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.ruby-version +1 -0
- data/API_FOR_EDITOR_INTEGRATION.md +97 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +107 -0
- data/Rakefile +2 -0
- data/bin/working_set +4 -0
- data/lib/api_input_actor.rb +75 -0
- data/lib/basic_actor.rb +8 -0
- data/lib/colors.rb +16 -0
- data/lib/live_updater_actor.rb +29 -0
- data/lib/set_builder_actor.rb +23 -0
- data/lib/set_builder_adapter.rb +2 -0
- data/lib/set_builder_adapter/ag.rb +132 -0
- data/lib/set_viewer_actor.rb +146 -0
- data/lib/user_input_actor.rb +177 -0
- data/lib/view/base.rb +13 -0
- data/lib/view/help.rb +28 -0
- data/lib/view/welcome_user.rb +40 -0
- data/lib/view/working_set.rb +313 -0
- data/lib/working_set.rb +34 -0
- data/lib/working_set_cli.rb +205 -0
- data/lib/working_set_item.rb +40 -0
- data/working_set.gemspec +35 -0
- metadata +226 -0
data/lib/view/base.rb
ADDED
data/lib/view/help.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class View::Help < View::Base
|
2
|
+
|
3
|
+
def self.render
|
4
|
+
new.render
|
5
|
+
end
|
6
|
+
|
7
|
+
def render
|
8
|
+
UserInputActor.set_user_input_mode :help
|
9
|
+
stdscr.clear
|
10
|
+
stdscr.move 0, 0
|
11
|
+
stdscr.printw "Key Bindings\n"
|
12
|
+
stdscr.printw "------------\n\n"
|
13
|
+
|
14
|
+
UserInputActor::USER_INPUT_MAPPINGS.each_pair do |k,v|
|
15
|
+
with_color(stdscr, :cyan) do
|
16
|
+
stdscr.printw " #{v[:key_desc] || k}"
|
17
|
+
end
|
18
|
+
stdscr.printw " - #{v[:desc]}\n\n"
|
19
|
+
end
|
20
|
+
with_color(stdscr, :blue) do
|
21
|
+
stdscr.printw "Press 'q' to go back."
|
22
|
+
end
|
23
|
+
|
24
|
+
stdscr.refresh
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class View::WelcomeUser < View::Base
|
2
|
+
|
3
|
+
def self.render
|
4
|
+
new.render
|
5
|
+
end
|
6
|
+
|
7
|
+
def render
|
8
|
+
UserInputActor.set_user_input_mode :welcome_user
|
9
|
+
stdscr.clear
|
10
|
+
print_centered \
|
11
|
+
[:cyan, "Working Set"],
|
12
|
+
"",
|
13
|
+
"v#{WorkingSet::VERSION}",
|
14
|
+
"by Jim Garvin et al.",
|
15
|
+
"",
|
16
|
+
[:blue, "Press '?' for help."],
|
17
|
+
[:blue, "Press 'q' to quit."]
|
18
|
+
stdscr.refresh
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def print_centered(*lines)
|
24
|
+
start_y = Ncurses.LINES / 2 - lines.size / 2
|
25
|
+
lines.each_with_index do |line, i|
|
26
|
+
color, msg = if Array === line
|
27
|
+
line
|
28
|
+
else
|
29
|
+
[:white, line]
|
30
|
+
end
|
31
|
+
x = Ncurses.COLS / 2 - msg.size / 2
|
32
|
+
stdscr.move start_y + i, x
|
33
|
+
with_color(stdscr, color) do
|
34
|
+
stdscr.printw msg
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,313 @@
|
|
1
|
+
# +--------------------------------------------------------------------------+
|
2
|
+
# | Search or Working Set Name + (indicates dirty/saved state) |
|
3
|
+
# +--------------------------------------------------------------------------+
|
4
|
+
# | Note if present |
|
5
|
+
# +--------------------------------------------------------------------------+
|
6
|
+
# | |
|
7
|
+
# | app/models/foo.rb |
|
8
|
+
# | 10 def foo |
|
9
|
+
# | > 11 puts "bar" (highlight match) |
|
10
|
+
# | 12 end |
|
11
|
+
# | |
|
12
|
+
# | app/models/bar.rb |
|
13
|
+
# | 10 def bar |
|
14
|
+
# | 11 puts "foo" (highlight match) |
|
15
|
+
# | 12 end |
|
16
|
+
# | |
|
17
|
+
# | 10 def bar |
|
18
|
+
# | 11 puts "foo" (highlight match) |
|
19
|
+
# | 12 end |
|
20
|
+
# +--------------------------------------------------------------------------+
|
21
|
+
# | 1-10 of 16 items |
|
22
|
+
# +--------------------------------------------------------------------------+
|
23
|
+
#
|
24
|
+
# * Highlight "selected item" with colors.
|
25
|
+
|
26
|
+
class View::WorkingSet < View::Base
|
27
|
+
attr_accessor :working_set, :selected_item_index, :file_index, :scroll_top, :scrollable_height, :show_match_lines
|
28
|
+
|
29
|
+
TITLE_ROWS = 2
|
30
|
+
FOOTER_ROWS = 2
|
31
|
+
|
32
|
+
def self.render(working_set)
|
33
|
+
new(working_set).render
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(working_set)
|
37
|
+
self.working_set = working_set
|
38
|
+
self.file_index = index_files(working_set)
|
39
|
+
self.selected_item_index = 0
|
40
|
+
self.scroll_top = 0
|
41
|
+
self.show_match_lines = true
|
42
|
+
end
|
43
|
+
|
44
|
+
def index_files(working_set)
|
45
|
+
index = {}
|
46
|
+
prev_file = nil
|
47
|
+
sorted_items.each_with_index do |item, idx|
|
48
|
+
if prev_file == nil
|
49
|
+
# first item in set
|
50
|
+
prev_file = index[item.file_path] = { file_path: item.file_path, item_index: idx, prev_file: nil }
|
51
|
+
elsif item.file_path == prev_file[:file_path]
|
52
|
+
# another match within file, ignore it.
|
53
|
+
else
|
54
|
+
# next file
|
55
|
+
current_file = index[item.file_path] = { file_path: item.file_path, item_index: idx, prev_file: prev_file }
|
56
|
+
prev_file[:next_file] = current_file
|
57
|
+
prev_file = current_file
|
58
|
+
end
|
59
|
+
end
|
60
|
+
index
|
61
|
+
end
|
62
|
+
|
63
|
+
def selected_item
|
64
|
+
sorted_items[selected_item_index]
|
65
|
+
end
|
66
|
+
|
67
|
+
def restore_selection_state(from_working_set_view)
|
68
|
+
if idx = sorted_items.find_index(from_working_set_view.selected_item)
|
69
|
+
self.selected_item_index = idx
|
70
|
+
self.show_match_lines = from_working_set_view.show_match_lines
|
71
|
+
render_items_and_footer # have to render to set @scrollable_line_count or the next call won't work
|
72
|
+
set_scroll_top(from_working_set_view.scroll_top)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def title
|
77
|
+
if working_set.name
|
78
|
+
"Name: #{working_set.name}"
|
79
|
+
else
|
80
|
+
"Search: #{working_set.search}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def note
|
85
|
+
working_set.note
|
86
|
+
end
|
87
|
+
|
88
|
+
def needs_save?
|
89
|
+
!working_set.saved
|
90
|
+
end
|
91
|
+
|
92
|
+
def sorted_items
|
93
|
+
@_sorted_items ||= working_set.items.sort_by { |i| [i.file_path, i.row.to_i] }
|
94
|
+
end
|
95
|
+
|
96
|
+
def render
|
97
|
+
UserInputActor.set_user_input_mode :working_set
|
98
|
+
stdscr.clear
|
99
|
+
stdscr.refresh
|
100
|
+
render_title.refresh
|
101
|
+
render_items.refresh
|
102
|
+
render_footer.refresh
|
103
|
+
end
|
104
|
+
|
105
|
+
def toggle_match_lines
|
106
|
+
self.show_match_lines = !show_match_lines
|
107
|
+
self.scroll_top = 0
|
108
|
+
@item_win.clear
|
109
|
+
render_items.refresh
|
110
|
+
end
|
111
|
+
|
112
|
+
def render_items_and_footer
|
113
|
+
render_items.refresh
|
114
|
+
render_footer.refresh
|
115
|
+
end
|
116
|
+
|
117
|
+
def select_next_file
|
118
|
+
next_file = file_index[selected_item.file_path][:next_file]
|
119
|
+
self.selected_item_index = next_file[:item_index] if next_file
|
120
|
+
render_items_and_footer
|
121
|
+
end
|
122
|
+
|
123
|
+
def select_prev_file
|
124
|
+
prev_file = file_index[selected_item.file_path][:prev_file]
|
125
|
+
self.selected_item_index = prev_file[:item_index] if prev_file
|
126
|
+
render_items_and_footer
|
127
|
+
end
|
128
|
+
|
129
|
+
def select_next_item
|
130
|
+
self.selected_item_index += 1 unless selected_item_index >= sorted_items.size - 1
|
131
|
+
render_items_and_footer
|
132
|
+
end
|
133
|
+
|
134
|
+
def select_prev_item
|
135
|
+
self.selected_item_index -= 1 unless selected_item_index <= 0
|
136
|
+
render_items_and_footer
|
137
|
+
end
|
138
|
+
|
139
|
+
def scroll(delta)
|
140
|
+
return if @scrollable_line_count <= scrollable_height
|
141
|
+
set_scroll_top(scroll_top + delta)
|
142
|
+
render_items_and_footer
|
143
|
+
end
|
144
|
+
|
145
|
+
def set_scroll_top(value)
|
146
|
+
self.scroll_top = if value < 2
|
147
|
+
# Reached top
|
148
|
+
0
|
149
|
+
elsif (value + scrollable_height) > @scrollable_line_count
|
150
|
+
# Reached bottom
|
151
|
+
[@scrollable_line_count - scrollable_height, 0].max
|
152
|
+
else
|
153
|
+
# Normal scroll
|
154
|
+
value
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def scrollable_height
|
159
|
+
Ncurses.LINES - TITLE_ROWS - FOOTER_ROWS
|
160
|
+
end
|
161
|
+
|
162
|
+
def scroll_bottom
|
163
|
+
scroll_top + scrollable_height
|
164
|
+
end
|
165
|
+
|
166
|
+
def render_title
|
167
|
+
# Height, Width, Y, X note: (0 width == full width)
|
168
|
+
@title_win ||= Ncurses.newwin(1, 0, 0, 0)
|
169
|
+
@title_win.move 0, 0
|
170
|
+
print_field @title_win, :left, calc_cols(1), " "
|
171
|
+
@title_win.move 0, 0
|
172
|
+
with_color @title_win, :blue do
|
173
|
+
@title_win.printw title
|
174
|
+
end
|
175
|
+
if working_set.options["whole_word"]
|
176
|
+
with_color @title_win, :red do
|
177
|
+
@title_win.printw " [w]"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
# if needs_save?
|
181
|
+
# with_color @title_win, :red do
|
182
|
+
# @title_win.printw " +"
|
183
|
+
# end
|
184
|
+
# end
|
185
|
+
@title_win
|
186
|
+
end
|
187
|
+
|
188
|
+
def render_footer
|
189
|
+
# Height, Width, Y, X note: (0 width == full width)
|
190
|
+
@footer_win ||= Ncurses.newwin(1, 0, Ncurses.LINES - 1, 0)
|
191
|
+
@footer_win.move 0, 0
|
192
|
+
with_color @footer_win, :blue do
|
193
|
+
print_field @footer_win, :right, calc_cols(1), "#{selected_item_index + 1} of #{sorted_items.size} (#{file_index.keys.size} files)"
|
194
|
+
end
|
195
|
+
@footer_win
|
196
|
+
end
|
197
|
+
|
198
|
+
def render_items
|
199
|
+
|
200
|
+
# Height, Width, Y, X note: (0 width == full width)
|
201
|
+
@item_win ||= Ncurses.newwin(scrollable_height, 0, TITLE_ROWS, 0)
|
202
|
+
|
203
|
+
previous_file_path = nil
|
204
|
+
previous_row = 0
|
205
|
+
@scrollable_line_number = 0
|
206
|
+
@scrollable_line_count = 0
|
207
|
+
|
208
|
+
sorted_items.each do |item|
|
209
|
+
|
210
|
+
if !show_match_lines
|
211
|
+
if item.file_path != previous_file_path
|
212
|
+
color = item.file_path == selected_item.file_path ? :cyan : :green
|
213
|
+
puts_scrollable_item 0, color, item.file_path
|
214
|
+
end
|
215
|
+
else
|
216
|
+
# Print file name if it's a new file, a "--" separator if it's the same
|
217
|
+
# file but non-consecutive lines, otherwise just nothing.
|
218
|
+
if item.file_path == previous_file_path
|
219
|
+
if item.row > previous_row + 1
|
220
|
+
puts_scrollable_item 0, :white, " --"
|
221
|
+
end
|
222
|
+
else
|
223
|
+
if previous_file_path
|
224
|
+
puts_scrollable_item 0, :white, ""
|
225
|
+
end
|
226
|
+
color = item.file_path == selected_item.file_path ? :cyan : :green
|
227
|
+
puts_scrollable_item 0, color, item.file_path
|
228
|
+
end
|
229
|
+
|
230
|
+
# Print pre-match lines.
|
231
|
+
item.pre_match_lines.each_with_index do |line, i|
|
232
|
+
print_scrollable_item 0, :white, " #{item.row - item.pre_match_lines.size + i}"
|
233
|
+
puts_scrollable_item 5, :white, line
|
234
|
+
end
|
235
|
+
|
236
|
+
# Record match line number
|
237
|
+
if item == selected_item
|
238
|
+
@selected_item_line_number = @scrollable_line_number
|
239
|
+
end
|
240
|
+
|
241
|
+
# Print match line.
|
242
|
+
print_scrollable_item 0, :blue, "#{item == selected_item ? ">" : " "}"
|
243
|
+
print_scrollable_item 2, :yellow, item.row
|
244
|
+
puts_scrollable_item 5, :yellow, item.match_line
|
245
|
+
|
246
|
+
# Print post-match lines.
|
247
|
+
item.post_match_lines.each_with_index do |line, i|
|
248
|
+
print_scrollable_item 0, :white, " #{item.row + 1 + i}"
|
249
|
+
puts_scrollable_item 5, :white, line
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
previous_file_path = item.file_path
|
254
|
+
previous_row = item.row + item.post_match_lines.size
|
255
|
+
end
|
256
|
+
|
257
|
+
@scrollable_line_count = @scrollable_line_number
|
258
|
+
|
259
|
+
@item_win
|
260
|
+
end
|
261
|
+
|
262
|
+
def puts_scrollable_item(start_col, color_name, content)
|
263
|
+
print_scrollable_item(start_col, color_name, content)
|
264
|
+
@scrollable_line_number += 1
|
265
|
+
end
|
266
|
+
|
267
|
+
def print_scrollable_item(start_col, color_name, content, *color_content_pairs)
|
268
|
+
if scrolled_into_view?(@scrollable_line_number)
|
269
|
+
y = scrollable_item_line_number_to_screen_row(@scrollable_line_number)
|
270
|
+
x = start_col
|
271
|
+
with_color @item_win, color_name do
|
272
|
+
@item_win.mvprintw y, x, "%-#{Ncurses.COLS - start_col}s", content
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def scrollable_item_line_number_to_screen_row(line_number)
|
278
|
+
line_number - scroll_top
|
279
|
+
end
|
280
|
+
|
281
|
+
def scrolled_into_view?(line_number, context_lines: 0)
|
282
|
+
result = (line_number - context_lines) >= scroll_top && (line_number + context_lines) < scroll_bottom
|
283
|
+
debug_message "scrolled_into_view line_number: #{line_number} context_lines: #{context_lines} result: #{result.inspect}"
|
284
|
+
result
|
285
|
+
end
|
286
|
+
|
287
|
+
def selected_item_in_view?
|
288
|
+
scrolled_into_view? @selected_item_line_number, context_lines: $CONTEXT_LINES
|
289
|
+
end
|
290
|
+
|
291
|
+
def selected_item_scroll_delta
|
292
|
+
scroll_padding = 2 + $CONTEXT_LINES
|
293
|
+
debug_message "scrolling #{@selected_item_line_number} | #{scroll_top} | #{scroll_bottom}"
|
294
|
+
if scroll_top > (@selected_item_line_number - $CONTEXT_LINES)
|
295
|
+
# scroll up
|
296
|
+
((scroll_top - @selected_item_line_number) * -1) - scroll_padding
|
297
|
+
elsif scroll_bottom < (@selected_item_line_number + $CONTEXT_LINES)
|
298
|
+
# scroll down
|
299
|
+
@selected_item_line_number - scroll_bottom + scroll_padding
|
300
|
+
else
|
301
|
+
0
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def print_field(window, align, width, content)
|
306
|
+
window.printw "%#{align == :left ? "-" : ""}#{width}s", content
|
307
|
+
end
|
308
|
+
|
309
|
+
def calc_cols(percentage)
|
310
|
+
(Ncurses.COLS * percentage).to_i
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
data/lib/working_set.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
class WorkingSet
|
4
|
+
attr_accessor :search, :options, :items, :name, :note, :saved
|
5
|
+
|
6
|
+
VERSION = "1.0.1"
|
7
|
+
|
8
|
+
def initialize(search = nil, options = nil, items = [])
|
9
|
+
self.search = search
|
10
|
+
self.options = options
|
11
|
+
self.items = []
|
12
|
+
items.each { |i| self.add i }
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(item)
|
16
|
+
if item.kind_of? WorkingSetItem
|
17
|
+
items.push item
|
18
|
+
else
|
19
|
+
items.push WorkingSetItem.new(item)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
str = <<EOS
|
25
|
+
WorkingSet #{object_id}
|
26
|
+
Search: #{search}
|
27
|
+
Options: #{options}
|
28
|
+
Items:
|
29
|
+
|
30
|
+
#{items.map(&:inspect).join("\n")}
|
31
|
+
EOS
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# DEV ONLY
|
2
|
+
# Among other things, this adds bundle-installed gems to the load path so the
|
3
|
+
# dependencies are require-able.
|
4
|
+
require 'bundler/setup' if ENV["WORKING_SET_DEV"] == "true"
|
5
|
+
|
6
|
+
# External gem dependencies are loaded here.
|
7
|
+
require 'celluloid/current'
|
8
|
+
require 'celluloid/io'
|
9
|
+
require 'ncurses'
|
10
|
+
require 'clipboard'
|
11
|
+
require 'tty-option'
|
12
|
+
|
13
|
+
# And zeitwerk takes care of auto-loading the ruby files in this gem.
|
14
|
+
require 'zeitwerk'
|
15
|
+
loader = Zeitwerk::Loader.for_gem
|
16
|
+
loader.setup
|
17
|
+
|
18
|
+
class WorkingSetCli
|
19
|
+
|
20
|
+
include TTY::Option
|
21
|
+
|
22
|
+
usage do
|
23
|
+
|
24
|
+
no_command # Doesn't seem to work as expected...
|
25
|
+
command nil # So I have to do this.
|
26
|
+
|
27
|
+
header "Working Set: A powerful companion for your favorite text editor."
|
28
|
+
|
29
|
+
desc "Working Set facilitates very fast searching powered by `ag`, has a convenient ncurses-based interface, and robust editor integration via bi-directional socket API."
|
30
|
+
desc "It pairs great with tmux and vim."
|
31
|
+
desc "See the README for more:\nhttps://github.com/coderifous/working_set"
|
32
|
+
|
33
|
+
example <<~EOS
|
34
|
+
Run with defaults:
|
35
|
+
$ working_set
|
36
|
+
EOS
|
37
|
+
|
38
|
+
example <<~EOS
|
39
|
+
Specify socket file:
|
40
|
+
$ working_set --socket=/tmp/ws_sock
|
41
|
+
EOS
|
42
|
+
|
43
|
+
example <<~EOS
|
44
|
+
Enable watching and auto-refresh for current directory:
|
45
|
+
$ working_set --watch
|
46
|
+
EOS
|
47
|
+
|
48
|
+
example <<~EOS
|
49
|
+
Enable watching and auto-refresh for specific directory, e.g. the app/ directory of a rails project:
|
50
|
+
$ working_set --watch app
|
51
|
+
EOS
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
flag :help do
|
56
|
+
short "-h"
|
57
|
+
long "--help"
|
58
|
+
desc "Print usage"
|
59
|
+
end
|
60
|
+
|
61
|
+
option :watch do
|
62
|
+
desc "Auto-refresh working set when file changes detected"
|
63
|
+
short "-w"
|
64
|
+
long "--watch=[path]"
|
65
|
+
end
|
66
|
+
|
67
|
+
option :socket do
|
68
|
+
desc "Set path for IPC socket file (for comms with text editor)"
|
69
|
+
short "-s"
|
70
|
+
long "--socket=path"
|
71
|
+
default ".working_set_socket"
|
72
|
+
end
|
73
|
+
|
74
|
+
option :context do
|
75
|
+
desc "How many lines around matches to show"
|
76
|
+
short "-c'"
|
77
|
+
long "--context=number"
|
78
|
+
convert :int
|
79
|
+
default 1
|
80
|
+
end
|
81
|
+
|
82
|
+
option :debug do
|
83
|
+
hidden
|
84
|
+
desc "Set path for debug logging."
|
85
|
+
short "-d"
|
86
|
+
long "--debug=[path]"
|
87
|
+
end
|
88
|
+
|
89
|
+
def run
|
90
|
+
parse
|
91
|
+
if params[:help]
|
92
|
+
print help
|
93
|
+
exit
|
94
|
+
else
|
95
|
+
init
|
96
|
+
$supervisor = AppSupervisor.run!
|
97
|
+
sleep 0.5 while $supervisor.alive? # I've need to occupy the main thread otherwise the program exits here.
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class AppSupervisor < Celluloid::Supervision::Container
|
102
|
+
supervise type: SetViewerActor, as: :set_viewer
|
103
|
+
supervise type: SetBuilderActor, as: :set_builder
|
104
|
+
supervise type: ApiInputActor, as: :api_input
|
105
|
+
supervise type: UserInputActor, as: :user_input
|
106
|
+
|
107
|
+
finalizer :clean_up_ncurses
|
108
|
+
|
109
|
+
def self.enable_live_watch!
|
110
|
+
supervise type: LiveUpdaterActor, as: :live_updater
|
111
|
+
end
|
112
|
+
|
113
|
+
# It seems exiting cleanly requires:
|
114
|
+
# - shutdown: to kill the supervised actors
|
115
|
+
# - terminate: to kill the supervisor itself
|
116
|
+
def do_shutdown
|
117
|
+
shutdown
|
118
|
+
terminate
|
119
|
+
end
|
120
|
+
|
121
|
+
def clean_up_ncurses
|
122
|
+
debug_message "cleaning up Ncurses"
|
123
|
+
Ncurses.echo
|
124
|
+
Ncurses.nocbreak
|
125
|
+
Ncurses.nl
|
126
|
+
Ncurses.endwin
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def init
|
134
|
+
init_debug
|
135
|
+
init_socket_file
|
136
|
+
init_live_watch
|
137
|
+
init_ncurses
|
138
|
+
$CONTEXT_LINES = params[:context]
|
139
|
+
end
|
140
|
+
|
141
|
+
def init_ncurses
|
142
|
+
Ncurses.initscr
|
143
|
+
Ncurses.cbreak # unbuffered input
|
144
|
+
Ncurses.noecho # turn off input echoing
|
145
|
+
Ncurses.nonl # turn off newline translation
|
146
|
+
Ncurses.stdscr.intrflush(false) # turn off flush-on-interrupt
|
147
|
+
Ncurses.stdscr.keypad(true) # turn on keypad mode
|
148
|
+
Ncurses.curs_set(0) # hidden cursor
|
149
|
+
|
150
|
+
Ncurses.start_color
|
151
|
+
Ncurses.use_default_colors
|
152
|
+
|
153
|
+
Colors.each_pair do |k,v|
|
154
|
+
Ncurses.init_pair v[:number], v[:pair][0], v[:pair][1]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def init_live_watch
|
159
|
+
AppSupervisor.enable_live_watch! if params.key?(:watch)
|
160
|
+
$LIVE_UPDATE_WATCH_PATH = params.key?(:watch) ? (params[:watch] || ".") : false
|
161
|
+
end
|
162
|
+
|
163
|
+
def init_socket_file
|
164
|
+
$SOCKET_PATH = params[:socket]
|
165
|
+
check_for_existing_socket_file
|
166
|
+
end
|
167
|
+
|
168
|
+
def check_for_existing_socket_file
|
169
|
+
if File.exists?($SOCKET_PATH)
|
170
|
+
puts "File #{$SOCKET_PATH.inspect} exists. Overwrite it? (y/N)"
|
171
|
+
require "io/console"
|
172
|
+
if STDIN.getch =~ /y/i
|
173
|
+
File.delete($SOCKET_PATH)
|
174
|
+
else
|
175
|
+
puts "Ok, exiting program."
|
176
|
+
exit
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def init_debug
|
182
|
+
if params.key?(:debug)
|
183
|
+
require 'tty-logger'
|
184
|
+
path = params[:debug] || "working_set.log"
|
185
|
+
log_file = File.open(path, "a")
|
186
|
+
log_file.sync = true
|
187
|
+
$logger = TTY::Logger.new do |config|
|
188
|
+
config.metadata = [:time]
|
189
|
+
config.level = :debug
|
190
|
+
config.output = log_file
|
191
|
+
end
|
192
|
+
Celluloid.logger = $logger
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
class Object
|
199
|
+
def debug_message(msg)
|
200
|
+
$logger.debug msg if $logger
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
WorkingSetCli.new.run
|
205
|
+
|