ruby-zoom 3.0.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.
@@ -0,0 +1,48 @@
1
+ require "shellwords"
2
+ require "zoom_profile"
3
+
4
+ class AckProfile < ZoomProfile
5
+ def colors
6
+ 'ACK_COLOR_LINENO=white ACK_COLOR_MATCH="black on_white"'
7
+ end
8
+
9
+ def exe(args, pattern)
10
+ if (pattern.nil? || pattern.empty?)
11
+ system(
12
+ "#{self.to_s} --pager \"#{@pager}\" #{args} " \
13
+ "#{self.append}"
14
+ )
15
+ else
16
+ system(
17
+ "#{self.to_s} --pager \"#{@pager}\" #{args} " \
18
+ "#{pattern.shellescape} #{self.append}"
19
+ )
20
+ end
21
+ end
22
+
23
+ def initialize(
24
+ operator = nil,
25
+ flags = "--smart-case",
26
+ envprepend = "",
27
+ append = ""
28
+ )
29
+ # Special case because of debian
30
+ operator = nil
31
+ if (ScoobyDoo.where_are_you("ack"))
32
+ operator = "ack"
33
+ elsif (ScoobyDoo.where_are_you("ack-grep"))
34
+ operator = "ack-grep"
35
+ else
36
+ # Oops
37
+ operator = "echo"
38
+ if (operator == "echo")
39
+ flags = "#"
40
+ envprepend = ""
41
+ append = ""
42
+ end
43
+ end
44
+
45
+ super(operator, flags, envprepend, append)
46
+ @taggable = true
47
+ end
48
+ end
@@ -0,0 +1,41 @@
1
+ require "shellwords"
2
+ require "zoom_profile"
3
+
4
+ class AgProfile < ZoomProfile
5
+ def colors
6
+ '--color-match "47;1;30" --color-line-number "0;37"'
7
+ end
8
+
9
+ def exe(args, pattern)
10
+ if (pattern.nil? || pattern.empty?)
11
+ system(
12
+ "#{self.to_s} --pager \"#{@pager}\" #{args} " \
13
+ "#{self.append}"
14
+ )
15
+ else
16
+ system(
17
+ "#{self.to_s} --pager \"#{@pager}\" #{args} " \
18
+ "#{pattern.shellescape} #{self.append}"
19
+ )
20
+ end
21
+ end
22
+
23
+ def initialize(
24
+ operator = nil,
25
+ flags = "-S",
26
+ envprepend = "",
27
+ append = ""
28
+ )
29
+ super("ag", flags, envprepend, append)
30
+ @taggable = true
31
+ end
32
+
33
+ def to_s
34
+ [
35
+ self["prepend"],
36
+ self["operator"],
37
+ self.colors,
38
+ self["flags"]
39
+ ].join(" ").strip
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ require "shellwords"
2
+ require "zoom_profile"
3
+
4
+ class FindProfile < ZoomProfile
5
+ def exe(args, pattern)
6
+ if (pattern.nil? || pattern.empty?)
7
+ system(
8
+ "#{self.to_s} #{args} \"*\" #{self.append} | " \
9
+ "#{@pager}"
10
+ )
11
+ else
12
+ system(
13
+ "#{self.to_s} #{args} \"#{pattern}\" " \
14
+ "#{self.append} | #{@pager}"
15
+ )
16
+ end
17
+ end
18
+
19
+ def initialize(
20
+ operator = nil,
21
+ flags = ". -name",
22
+ envprepend = "",
23
+ append = ""
24
+ )
25
+ super("find", flags, envprepend, append)
26
+ @taggable = true
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ require "shellwords"
2
+ require "zoom_profile"
3
+
4
+ class GrepProfile < ZoomProfile
5
+ def colors
6
+ [
7
+ 'GREP_COLORS="',
8
+ "fn=1;32:",
9
+ "ln=0;37:",
10
+ "ms=47;1;30:",
11
+ "mc=47;1;30:",
12
+ "sl=:cx=:bn=:se=",
13
+ '"'
14
+ ].join.strip
15
+ end
16
+
17
+ def exe(args, pattern)
18
+ # Emulate ag/ack as much as possible
19
+ if (pattern.nil? || pattern.empty?)
20
+ system(
21
+ "#{self.to_s} #{args} #{self.append} | " \
22
+ "sed \"s|\\[K[:-]|\\[K\\n|\" | #{@pager}"
23
+ )
24
+ else
25
+ system(
26
+ "#{self.to_s} #{args} #{pattern.shellescape} " \
27
+ "#{self.append} | sed \"s|\\[K[:-]|\\[K\\n|\" | " \
28
+ "#{@pager}"
29
+ )
30
+ end
31
+ end
32
+
33
+ def initialize(
34
+ operator = nil,
35
+ flags = [
36
+ "--color=always",
37
+ "-EHIinR",
38
+ "--exclude-dir=.bzr",
39
+ "--exclude-dir=.git",
40
+ "--exclude-dir=.svn"
41
+ ].join(" ").strip,
42
+ envprepend = "",
43
+ append = "."
44
+ )
45
+ super("grep", flags, envprepend, append)
46
+ @taggable = true
47
+ end
48
+ end
@@ -0,0 +1,67 @@
1
+ require "ag_profile"
2
+ require "ack_profile"
3
+ require "grep_profile"
4
+ require "shellwords"
5
+ require "zoom_profile"
6
+
7
+ class PasswordsProfile < ZoomProfile
8
+ def colors
9
+ return @profile.colors
10
+ end
11
+
12
+ def exe(args, pattern)
13
+ @profile.exe(args, pattern)
14
+ end
15
+
16
+ def info
17
+ [
18
+ "Class : #{self.class.to_s}",
19
+ "Prepend : #{@profile.prepend}",
20
+ "Operator: #{@profile.operator}",
21
+ "Flags : #{@profile.flags}",
22
+ "Append : #{@profile.append}"
23
+ ].join("\n").strip
24
+ end
25
+
26
+ def initialize(
27
+ operator = nil,
28
+ flags = "",
29
+ envprepend = "",
30
+ append = ""
31
+ )
32
+ @passwd_regex = "\"pass(word|wd)?[^:=,>]? *[:=,>]\""
33
+
34
+ if (ScoobyDoo.where_are_you("ag"))
35
+ @profile = AgProfile.new(nil, "-uS", "", @passwd_regex)
36
+ elsif (
37
+ ScoobyDoo.where_are_you("ack") ||
38
+ ScoobyDoo.where_are_you("ack-grep")
39
+ )
40
+ @profile = AckProfile.new(
41
+ nil,
42
+ "--smart-case",
43
+ "",
44
+ @passwd_regex
45
+ )
46
+ else
47
+ @profile = GrepProfile.new(
48
+ nil,
49
+ "--color=always -EHinR",
50
+ "",
51
+ @passwd_regex
52
+ )
53
+ end
54
+
55
+ super(
56
+ @profile.operator,
57
+ @profile.flags,
58
+ @profile.prepend,
59
+ @profile.append
60
+ )
61
+ @taggable = true
62
+ end
63
+
64
+ def to_s
65
+ return @porfile.to_s
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ # Redefine String class to allow for colorizing and rsplit
2
+ class String
3
+ def blue
4
+ return colorize(36)
5
+ end
6
+
7
+ def colorize(color)
8
+ return "\e[#{color}m#{self}\e[0m"
9
+ end
10
+
11
+ def green
12
+ return colorize(32)
13
+ end
14
+
15
+ def red
16
+ return colorize(31)
17
+ end
18
+
19
+ def white
20
+ return colorize(37)
21
+ end
22
+
23
+ def word_wrap(width = 70)
24
+ return scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/).join("\n")
25
+ end
26
+ end
@@ -0,0 +1,621 @@
1
+ require "ack_profile"
2
+ require "ag_profile"
3
+ require "find_profile"
4
+ require "grep_profile"
5
+ require "io/wait"
6
+ require "json"
7
+ require "pathname"
8
+ require "passwords_profile"
9
+ require "singleton"
10
+ require "string"
11
+ require "zoom_error"
12
+ require "zoom_profile"
13
+
14
+ class Zoom
15
+ include Singleton
16
+ include ZoomError
17
+
18
+ def add_profile(
19
+ name,
20
+ clas,
21
+ operator = nil,
22
+ flags = nil,
23
+ envprepend = nil,
24
+ append = nil
25
+ )
26
+ if (@profiles.has_key?(name))
27
+ raise ZoomError::ProfileAlreadyExistsError.new(name)
28
+ end
29
+
30
+ default_class = nil
31
+ begin
32
+ default_class = Object::const_get(clas).new
33
+ rescue NameError => e
34
+ raise ZoomError::ProfileClassUnknownError.new(clas)
35
+ end
36
+
37
+ edit_profile(
38
+ name,
39
+ default_class,
40
+ operator,
41
+ flags,
42
+ envprepend,
43
+ append
44
+ )
45
+ end
46
+
47
+ def clear_cache
48
+ @cache_file.delete if (@cache_file.exist?)
49
+ end
50
+
51
+ def configure_editor(editor)
52
+ e = ScoobyDoo.where_are_you(editor)
53
+ if (e.nil?)
54
+ raise ZoomError::ExecutableNotFoundError.new(editor)
55
+ end
56
+
57
+ @rc["editor"] = e
58
+ write_zoomrc
59
+ end
60
+
61
+ def default
62
+ default_zoominfo
63
+ default_zoomrc
64
+ end
65
+
66
+ def default_zoominfo
67
+ @info = Hash.new
68
+ @info["profile"] = "default"
69
+
70
+ # Reset last command to be empty
71
+ @info["last_command"] = Hash.new
72
+
73
+ write_zoominfo
74
+ end
75
+ private :default_zoominfo
76
+
77
+ def default_zoomrc
78
+ @rc = Hash.new
79
+ @profiles = Hash.new
80
+
81
+ all = nil
82
+
83
+ # Default ag profiles
84
+ if (ScoobyDoo.where_are_you("ag"))
85
+ ag = AgProfile.new
86
+ all = AgProfile.new(nil, "-uS")
87
+ else
88
+ ag = nil
89
+ end
90
+
91
+ # Default ack profile
92
+ if (
93
+ ScoobyDoo.where_are_you("ack") ||
94
+ ScoobyDoo.where_are_you("ack-grep")
95
+ )
96
+ ack = AckProfile.new
97
+ else
98
+ ack = nil
99
+ end
100
+
101
+ # Default grep profile (emulate ag/ack as much as possible)
102
+ grep = GrepProfile.new
103
+ if (all.nil?)
104
+ all = GrepProfile.new
105
+ all.flags("--color=always -EHinR")
106
+ end
107
+
108
+ # Create default profile
109
+ if (ag)
110
+ default = ag
111
+ elsif (ack)
112
+ default = ack
113
+ else
114
+ default = grep
115
+ end
116
+
117
+ # Create find profile
118
+ find = FindProfile.new
119
+
120
+ # Put profiles into rc
121
+ @profiles["ack"] = ack if (ack)
122
+ @profiles["ag"] = ag if (ag)
123
+ @profiles["all"] = all if (all)
124
+ @profiles["default"] = default
125
+ @profiles["grep"] = grep
126
+ @profiles["passwords"] = PasswordsProfile.new
127
+ @profiles["zoom_find"] = find
128
+
129
+ # Default editor (use $EDITOR)
130
+ @rc["editor"] = ""
131
+
132
+ write_zoomrc
133
+ end
134
+ private :default_zoomrc
135
+
136
+ def delete_profile(name)
137
+ if (name == "default")
138
+ raise ZoomError::ProfileCanNotBeModifiedError.new(name)
139
+ end
140
+
141
+ if (name == "zoom_find")
142
+ raise ZoomError::ProfileCanNotBeModifiedError.new(name)
143
+ end
144
+
145
+ if (!@profiles.has_key?(name))
146
+ raise ZoomError::ProfileDoesNotExistError.new(name)
147
+ end
148
+
149
+ @profiles.delete(name)
150
+ write_zoomrc
151
+
152
+ if (name == @info["profile"])
153
+ @info["profile"] = "default"
154
+ write_zoominfo
155
+ end
156
+ end
157
+
158
+ def edit_profile(
159
+ name,
160
+ profile = nil,
161
+ operator = nil,
162
+ flags = nil,
163
+ envprepend = nil,
164
+ append = nil
165
+ )
166
+ if (name == "zoom_find")
167
+ raise ZoomError::ProfileCanNotBeModified.new(name)
168
+ end
169
+
170
+ profile = @profiles[name] if (profile.nil?)
171
+
172
+ if (profile.nil?)
173
+ raise ZoomError::ProfileDoesNotExists.new(name)
174
+ end
175
+
176
+ profile.operator(operator) if (operator)
177
+ profile.flags(flags) if (flags)
178
+ profile.prepend(envprepend) if (envprepend)
179
+ profile.append(append) if (append)
180
+
181
+ @profiles[name] = profile
182
+ write_zoomrc
183
+ end
184
+
185
+ def exec_profile(name, args, pattern)
186
+ name = @info["profile"] if (name.nil?)
187
+
188
+ if (!@profiles.has_key?(name))
189
+ raise ZoomError::ProfileDoesNotExistError.new(name)
190
+ end
191
+
192
+ @info["last_command"] = {
193
+ "profile" => name,
194
+ "subargs" => args.nil? ? "": args,
195
+ "pattern" => pattern.nil? ? "" : pattern
196
+ }
197
+ write_zoominfo
198
+
199
+ profile = @profiles[name]
200
+ begin
201
+ clear_cache if (profile.taggable)
202
+ profile.exe(args, pattern)
203
+ shortcut_cache(profile) if (profile.taggable)
204
+ rescue Interrupt
205
+ # ^C
206
+ end
207
+ end
208
+
209
+ def get_location_of_result(result)
210
+ count = 0
211
+ File.open(@shortcut_file) do |file|
212
+ file.each do |line|
213
+ count += 1
214
+ if (count == result)
215
+ return line
216
+ end
217
+ end
218
+ end
219
+ return nil
220
+ end
221
+ private :get_location_of_result
222
+
223
+ def get_new_value(val, default)
224
+ return default if (val.nil? || val.empty?)
225
+ return "" if (val.downcase == "empty")
226
+ return "" if (val.downcase == "\"empty\"")
227
+ return val
228
+ end
229
+ private :get_new_value
230
+
231
+ def initialize
232
+ # Load custom profiles
233
+ custom_profs = Pathname.new("~/.zoom_profiles.rb").expand_path
234
+ require_relative custom_profs if (custom_profs.exist?)
235
+
236
+ @cache_file = Pathname.new("~/.zoom_cache").expand_path
237
+ @info_file = Pathname.new("~/.zoominfo").expand_path
238
+ @rc_file = Pathname.new("~/.zoomrc").expand_path
239
+ @shortcut_file = Pathname.new("~/.zoom_shortcuts").expand_path
240
+
241
+ read_zoomrc
242
+ read_zoominfo
243
+
244
+ # Setup editor
245
+ @editor = @rc["editor"]
246
+ @editor = ENV["EDITOR"] if (@editor.nil? || @editor.empty?)
247
+ @editor = "vim" if (@editor.nil? || @editor.empty?)
248
+ @editor = ScoobyDoo.where_are_you(@editor)
249
+ @editor = ScoobyDoo.where_are_you("vi") if (@editor.nil?)
250
+ end
251
+
252
+ def interactive_add_profile(name)
253
+ if (@profiles.has_key?(name))
254
+ raise ZoomError::ProfileAlreadyExistsError.new(name)
255
+ end
256
+
257
+ default_op = "grep"
258
+ if (ScoobyDoo.where_are_you("ag"))
259
+ default_op = "ag"
260
+ elsif (ScoobyDoo.where_are_you("ack"))
261
+ default_op = "ack"
262
+ elsif (ScoobyDoo.where_are_you("ack-grep"))
263
+ default_op = "ack-grep"
264
+ end
265
+
266
+ case default_op
267
+ when "ack", "ack-grep"
268
+ puts "Enter class (default AckProfile):"
269
+ when "ag"
270
+ puts "Enter class (default AgProfile):"
271
+ when "grep"
272
+ puts "Enter class (default GrepProfile):"
273
+ end
274
+
275
+ clas = gets.chomp
276
+ puts if (clas && !clas.empty?)
277
+
278
+ case default_op
279
+ when "ack", "ack-grep"
280
+ clas = "AckProfile" if (clas.nil? || clas.empty?)
281
+ when "ag"
282
+ clas = "AgProfile" if (clas.nil? || clas.empty?)
283
+ when "grep"
284
+ clas = "GrepProfile" if (clas.nil? || clas.empty?)
285
+ end
286
+
287
+ add_profile(name, clas)
288
+ interactive_edit_profile(name)
289
+ end
290
+
291
+ def interactive_edit_profile(name, profile = nil)
292
+ if (name == "zoom_find")
293
+ raise ZoomError::ProfileCanNotBeModifiedError.new(name)
294
+ end
295
+
296
+ profile = @profiles[name] if (profile.nil?)
297
+
298
+ if (profile.nil?)
299
+ raise ZoomError::ProfileDoesNotExistError.new(name)
300
+ end
301
+
302
+ # Get new operator
303
+ puts "Enter operator (default #{profile.operator}):"
304
+
305
+ op = ScoobyDoo.where_are_you(gets.chomp)
306
+ puts if (op && !op.empty?)
307
+ op = profile.operator if (op.nil? || op.empty?)
308
+
309
+ # Get new flags
310
+ puts "For empty string put \"empty\""
311
+ puts "Enter flags (default \"#{profile.flags}\"):"
312
+
313
+ flags = gets.chomp
314
+ puts if (flags && !flags.empty?)
315
+ flags = get_new_value(flags, profile.flags)
316
+
317
+ # Get new prepend
318
+ puts "For empty string put \"empty\""
319
+ puts "Enter prepend (default \"#{profile.prepend}\"):"
320
+
321
+ envprepend = gets.chomp
322
+ puts if (envprepend && !envprepend.empty?)
323
+ envprepend = get_new_value(envprepend, profile.prepend)
324
+
325
+ # Get new append
326
+ puts "For empty string put \"empty\""
327
+ puts "Enter append (default \"#{profile.append}\"):"
328
+
329
+ append = gets.chomp
330
+ puts if (append && !append.empty?)
331
+ append = get_new_value(append, profile.append)
332
+
333
+ edit_profile(name, profile, op, flags, envprepend, append)
334
+ end
335
+
336
+ def list_profile_names
337
+ @profiles.keys.sort.each do |name|
338
+ puts name
339
+ end
340
+ end
341
+
342
+ def list_profiles
343
+ @profiles.keys.sort.each do |name|
344
+ if (name == @info["profile"])
345
+ puts "### #{name} ###".green
346
+ else
347
+ puts "### #{name} ###"
348
+ end
349
+ puts @profiles[name].info
350
+ puts
351
+ end
352
+ end
353
+
354
+ def list_tags
355
+ return if (!@cache_file.exist?)
356
+
357
+ # Open shortcut file for writing
358
+ shct = File.open(@shortcut_file, "r")
359
+
360
+ # Read in cache
361
+ File.open(@cache_file) do |cache|
362
+ count = 1
363
+
364
+ cache.each do |line|
365
+ line.chomp!
366
+ plain = remove_colors(line)
367
+ if (line.start_with?("ZOOM_EXE_DIR="))
368
+ # Ignore this line
369
+ elsif ((line == "-") || (line == "--") || line.empty?)
370
+ # Ignore dividers when searching with context and
371
+ # empty lines
372
+ elsif (plain.scan(/^[0-9]+[:-]/).empty?)
373
+ if (!plain.scan(/^\.\//).empty?)
374
+ # Operator was probably find
375
+ puts count
376
+ count += 1
377
+ end
378
+ else
379
+ puts count
380
+ count += 1
381
+ end
382
+ end
383
+ end
384
+ end
385
+
386
+ def loop_through_results(results)
387
+ tags = parse_tags(results)
388
+ return if (tags.empty?)
389
+
390
+ tag = tags.delete_at(0)
391
+ open_editor_to_result(tag)
392
+
393
+ tags.each do |tag|
394
+ print "Do you want to open result #{tag} [y]/n/q/l?: "
395
+
396
+ answer = nil
397
+ while (answer.nil?)
398
+ begin
399
+ system("stty raw -echo")
400
+ if ($stdin.ready?)
401
+ answer = $stdin.getc
402
+ else
403
+ sleep 0.1
404
+ end
405
+ ensure
406
+ system("stty -raw echo")
407
+ end
408
+ end
409
+ puts
410
+
411
+ case answer
412
+ when "n", "N"
413
+ # Do nothing
414
+ when "l", "L"
415
+ # Open this result then exit
416
+ open_editor_to_result(tag)
417
+ return
418
+ when "q", "Q", "\x03"
419
+ # Quit or ^C
420
+ return
421
+ else
422
+ open_editor_to_result(tag)
423
+ end
424
+ end
425
+ end
426
+
427
+ def open_editor_to_result(result)
428
+ loc = get_location_of_result(result.to_i)
429
+ if (loc)
430
+ system("#{@editor} #{loc}")
431
+ else
432
+ puts "Invalid tag \"#{result}\"!"
433
+ end
434
+ end
435
+ private :open_editor_to_result
436
+
437
+ def pager
438
+ File.open(@cache_file, "w") do |f|
439
+ f.write("ZOOM_EXE_DIR=#{Dir.pwd}\n")
440
+ begin
441
+ $stdin.each_line do |line|
442
+ f.write(line)
443
+ end
444
+ rescue Interrupt
445
+ # ^C
446
+ end
447
+ end
448
+ end
449
+
450
+ def parse_tags(results)
451
+ tags = Array.new
452
+ results.split(",").each do |num|
453
+ if (!num.scan(/^[0-9]+$/).empty?)
454
+ tags.push(num.to_i)
455
+ elsif (!num.scan(/^[0-9]+-[0-9]+$/).empty?)
456
+ range = num.split("-")
457
+ (range[0].to_i..range[1].to_i).each do |i|
458
+ tags.push(i)
459
+ end
460
+ else
461
+ puts "Tag #{num} not formatted properly. Ignoring."
462
+ end
463
+ end
464
+ return tags
465
+ end
466
+ private :parse_tags
467
+
468
+ def read_zoominfo
469
+ if (!@info_file.exist? && !@info_file.symlink?)
470
+ default_zoominfo
471
+ end
472
+
473
+ @info = JSON.parse(File.read(@info_file))
474
+ end
475
+ private :read_zoominfo
476
+
477
+ def read_zoomrc
478
+ default_zoomrc if (!@rc_file.exist? && !@rc_file.symlink?)
479
+
480
+ @rc = JSON.parse(File.read(@rc_file))
481
+ @profiles = Hash.new
482
+ @rc["profiles"].each do |name, prof|
483
+ @profiles[name] = ZoomProfile.from_json(prof)
484
+ end
485
+ @rc["profiles"] = @profiles
486
+ end
487
+ private :read_zoomrc
488
+
489
+ def rename_profile(rename, name = nil)
490
+ name = @info["profile"] if (name.nil?)
491
+
492
+ if ((name == "default") || (name == "zoom_find"))
493
+ raise ZoomError::ProfileCanNotBeModifiedError.new(name)
494
+ end
495
+
496
+ if (!@profiles.has_key?(name))
497
+ raise ZoomError::ProfileDoesNotExistError.new(name)
498
+ end
499
+
500
+ if (@profiles.has_key?(rename))
501
+ raise ZoomError::ProfileAlreadyExistsError.new(rename)
502
+ end
503
+
504
+ @profiles[rename] = @profiles[name]
505
+ @profiles.delete(name)
506
+ write_zoomrc
507
+
508
+ if (name == @info["profile"])
509
+ @info["profile"] = rename
510
+ write_zoominfo
511
+ end
512
+ end
513
+
514
+ def repeat
515
+ return if (@info["last_command"].empty?)
516
+
517
+ exe_command(
518
+ @info["last_command"]["profile"],
519
+ @info["last_command"]["subargs"],
520
+ @info["last_command"]["pattern"]
521
+ )
522
+ end
523
+
524
+ def remove_colors(str)
525
+ str.unpack("C*").pack("U*").gsub(/\e\[([0-9;]*m|K)/, "")
526
+ end
527
+ private :remove_colors
528
+
529
+ def shortcut_cache(profile = nil)
530
+ return if (!@cache_file.exist?)
531
+ return if (@info["last_command"].empty?)
532
+
533
+ if (profile.nil?)
534
+ profile = @profiles[@info["last_command"]["profile"]]
535
+ end
536
+
537
+ # Open shortcut file for writing
538
+ shct = File.open(@shortcut_file, "w")
539
+
540
+ # Read in cache
541
+ File.open(@cache_file) do |cache|
542
+ start_dir = ""
543
+ file = nil
544
+ filename = ""
545
+ first_time = true
546
+ count = 1
547
+
548
+ cache.each do |line|
549
+ line.chomp!
550
+ plain = remove_colors(line)
551
+ if (line.start_with?("ZOOM_EXE_DIR="))
552
+ # Get directory where search was ran
553
+ start_dir = line.gsub("ZOOM_EXE_DIR=", "")
554
+ elsif ((line == "-") || (line == "--") || line.empty?)
555
+ # Ignore dividers when searching with context and
556
+ # empty lines
557
+ elsif (plain.scan(/^[0-9]+[:-]/).empty?)
558
+ operator = profile.operator.split("/").last
559
+ if (operator != "find")
560
+ if (file != line)
561
+ # Filename
562
+ file = line
563
+ filename = remove_colors(file)
564
+
565
+ puts if (!first_time)
566
+ first_time = false
567
+
568
+ puts "\e[0m#{file}"
569
+ end
570
+ else
571
+ # Operator was find
572
+ puts "\e[1;31m[#{count}]\e[0m #{line}"
573
+ shct.write("'#{start_dir}/#{line}'\n")
574
+ count += 1
575
+ end
576
+ elsif (file)
577
+ # Match
578
+ sanitized = line.unpack("C*").pack("U*")
579
+ .gsub(/[\u0080-\u00ff]+/, "\1".dump[1..-2])
580
+ puts "\e[1;31m[#{count}]\e[0m #{sanitized}"
581
+
582
+ lineno = remove_colors(line).split(/[:-]/)[0]
583
+ shct.write(
584
+ "+#{lineno} '#{start_dir}/#{filename}'\n"
585
+ )
586
+
587
+ count += 1
588
+ end
589
+ end
590
+ end
591
+ end
592
+
593
+ def show_current
594
+ puts "### #{@info["profile"]} ###".green
595
+ puts @profiles[@info["profile"]].info
596
+ end
597
+
598
+ def switch_profile(name)
599
+ if (!@profiles.has_key?(name))
600
+ raise ZoomError::ProfileDoesNotExistError.new(name)
601
+ end
602
+
603
+ @info["profile"] = name
604
+ write_zoominfo
605
+ end
606
+
607
+ def write_zoominfo
608
+ File.open(@info_file, "w") do |file|
609
+ file.write(JSON.pretty_generate(@info))
610
+ end
611
+ end
612
+ private :write_zoominfo
613
+
614
+ def write_zoomrc
615
+ @rc["profiles"] = @profiles
616
+ File.open(@rc_file, "w") do |file|
617
+ file.write(JSON.pretty_generate(@rc))
618
+ end
619
+ end
620
+ private :write_zoomrc
621
+ end