ruby-zoom 3.5.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/bin/z +189 -147
  3. data/bin/zc +189 -147
  4. data/bin/zf +189 -147
  5. data/bin/zg +189 -147
  6. data/bin/zl +189 -147
  7. data/bin/zr +189 -147
  8. data/lib/zoom.rb +48 -604
  9. data/lib/zoom/cache.rb +253 -0
  10. data/lib/zoom/cache/result.rb +49 -0
  11. data/lib/zoom/config.rb +156 -0
  12. data/lib/zoom/editor.rb +121 -0
  13. data/lib/zoom/error.rb +6 -6
  14. data/lib/zoom/error/{executable_not_found_error.rb → executable_not_found.rb} +1 -3
  15. data/lib/zoom/error/invalid_color.rb +5 -0
  16. data/lib/zoom/error/{invalid_tag_error.rb → invalid_tag.rb} +1 -3
  17. data/lib/zoom/error/{profile_class_unknown_error.rb → profile_class_unknown.rb} +1 -3
  18. data/lib/zoom/error/{profile_does_not_exist_error.rb → profile_does_not_exist.rb} +1 -3
  19. data/lib/zoom/error/profile_not_named.rb +7 -0
  20. data/lib/zoom/profile.rb +162 -66
  21. data/lib/zoom/profile/ack.rb +5 -30
  22. data/lib/zoom/profile/ag.rb +2 -37
  23. data/lib/zoom/profile/find.rb +2 -25
  24. data/lib/zoom/profile/grep.rb +2 -44
  25. data/lib/zoom/profile/passwords.rb +27 -59
  26. data/lib/zoom/profile/pt.rb +2 -26
  27. data/lib/zoom/profile_manager.rb +49 -0
  28. data/lib/zoom/wish/add_wish.rb +58 -0
  29. data/lib/zoom/wish/color_wish.rb +147 -0
  30. data/lib/zoom/wish/copy_wish.rb +57 -0
  31. data/lib/zoom/wish/delete_wish.rb +51 -0
  32. data/lib/zoom/wish/edit_wish.rb +130 -0
  33. data/lib/zoom/wish/editor_wish.rb +31 -0
  34. data/lib/zoom/wish/list_wish.rb +58 -0
  35. data/lib/zoom/wish/rename_wish.rb +69 -0
  36. data/lib/zoom/wish/reset_wish.rb +40 -0
  37. data/lib/zoom/wish/use_wish.rb +61 -0
  38. metadata +118 -24
  39. data/lib/string.rb +0 -48
  40. data/lib/zoom/error/profile_already_exists_error.rb +0 -8
  41. data/lib/zoom/error/profile_can_not_be_modified_error.rb +0 -8
data/bin/zr CHANGED
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require "djinni"
4
+ require "fileutils"
5
+ require "hilighter"
3
6
  require "optparse"
4
7
  require "zoom"
5
8
 
@@ -8,7 +11,9 @@ class ZoomExit
8
11
  INVALID_OPTION = 1
9
12
  INVALID_ARGUMENT = 2
10
13
  MISSING_ARGUMENT = 3
11
- EXCEPTION = 4
14
+ EXTRA_ARGUMENTS = 4
15
+ EXCEPTION = 5
16
+ AMBIGUOUS_ARGUMENT = 6
12
17
  end
13
18
 
14
19
  def parse(args)
@@ -16,76 +21,50 @@ def parse(args)
16
21
  options["action"] = "exec"
17
22
  options["cache_file"] = nil
18
23
  options["use"] = nil
24
+ options["verbose"] = false
19
25
 
20
- info = "Do you like to search through code using ag, ack, or " \
21
- "grep? Good! This tool is for you! Zoom adds some " \
22
- "convenience to ag/ack/grep by allowing you to quickly " \
23
- "open your search results in your editor of choice. When " \
24
- "looking at large code-bases, it can be a pain to have to " \
25
- "scroll to find the filename of each result. Zoom prints a " \
26
- "tag number in front of each result that ag/ack/grep " \
27
- "outputs. Then you can quickly open that tag number with " \
28
- "Zoom to jump straight to the source. Zoom is even " \
29
- "persistent across all your sessions! You can search in " \
30
- "one terminal and jump to a tag in another terminal from " \
31
- "any directory!"
26
+ info = [
27
+ "Do you like to search through code using ag, ack, grep, or",
28
+ "pt? Good! This tool is for you! Zoom adds some convenience",
29
+ "to ag/ack/grep/pt by allowing you to quickly open your",
30
+ "search results in your editor of choice. When looking at",
31
+ "large code-bases, it can be a pain to have to scroll to",
32
+ "find the filename of each result. Zoom prints a tag number",
33
+ "in front of each result that ag/ack/grep/pt outputs. Then",
34
+ "you can quickly open that tag number with Zoom to jump",
35
+ "straight to the source. Zoom is even persistent across all",
36
+ "your sessions! You can search in one terminal and jump to a",
37
+ "tag in another terminal from any directory!"
38
+ ].join(" ")
32
39
 
33
40
  parser = OptionParser.new do |opts|
41
+ opts.summary_width = 25
42
+
34
43
  opts.banner =
35
- "Usage: #{File.basename($0)} [OPTIONS] <pattern>"
44
+ "Usage: #{File.basename($0)} [OPTIONS] [pattern]"
36
45
 
37
- opts.on(
38
- "-a",
39
- "--add=NAME",
40
- "Add a new profile with specified name"
41
- ) do |name|
42
- options["action"] = "add"
43
- options["use"] = name
46
+ opts.on("", "DESCRIPTION")
47
+
48
+ info.scan(/\S.{0,76}\S(?=\s|$)|\S+/).each do |line|
49
+ opts.on(" #{line}")
44
50
  end
45
51
 
52
+ opts.on("", "OPTIONS")
53
+
46
54
  opts.on("-c", "--cache", "Show previous results") do
47
55
  options["action"] = "cache"
48
56
  end
49
57
 
50
58
  opts.on(
59
+ "-o",
51
60
  "--cache-file=FILE",
52
- "Use the specified cache file"
61
+ "Use alternate cache"
53
62
  ) do |file|
54
63
  options["cache_file"] = file
55
64
  end
56
65
 
57
- opts.on(
58
- "-d",
59
- "--delete=NAME",
60
- "Delete profile with specified name"
61
- ) do |name|
62
- options["action"] = "delete"
63
- options["use"] = name
64
- end
65
-
66
- opts.on(
67
- "-e",
68
- "--edit=NAME",
69
- "Edit profile with specified name"
70
- ) do |name|
71
- options["action"] = "edit"
72
- options["use"] = name
73
- end
74
-
75
- opts.on(
76
- "--editor=EDITOR",
77
- "Use the specified editor"
78
- ) do |editor|
79
- options["action"] = "editor"
80
- options["use"] = editor
81
- end
82
-
83
- opts.on("--examples", "Show some examples") do
84
- options["action"] = "examples"
85
- end
86
-
87
- opts.on("--find", "Use the zoom_find profile") do
88
- options["use"] = "zoom_find"
66
+ opts.on("--find", "Use built-in find profile") do
67
+ options["use"] = "find"
89
68
  end
90
69
 
91
70
  opts.on(
@@ -106,65 +85,78 @@ def parse(args)
106
85
  options["action"] = "list_profiles"
107
86
  end
108
87
 
109
- opts.on(
110
- "--list-profile-names",
111
- "List profile names for completion functions"
112
- ) do
113
- options["action"] = "list_profile_names"
88
+ opts.on("-r", "--repeat", "Repeat last Zoom command") do
89
+ options["action"] = "repeat"
114
90
  end
115
91
 
116
- opts.on(
117
- "--list-tags",
118
- "List tags for completion functions"
119
- ) do
120
- options["action"] = "list_tags"
92
+ opts.on("-u", "--use=NAME", "Run specified profile") do |name|
93
+ options["use"] = name
121
94
  end
122
95
 
123
- opts.on(
124
- "--pager",
125
- "Treat Zoom as a pager (internal use only)"
126
- ) do
127
- options["action"] = "pager"
96
+ opts.on("-w", "--which", "Display current profile") do
97
+ options["action"] = "which"
128
98
  end
129
99
 
130
- opts.on("-r", "--repeat", "Repeat the last Zoom command") do
131
- options["action"] = "repeat"
100
+ opts.on("", "CONFIGURE_OPTIONS")
101
+
102
+ opts.on(
103
+ "--configure",
104
+ "Open prompt to edit profiles"
105
+ ) do
106
+ options["action"] = "configure"
132
107
  end
133
108
 
134
- opts.on("--rc", "Create default .zoomrc file") do
109
+ opts.on("--rc", "Create default config file") do
135
110
  options["action"] = "rc"
136
111
  end
137
112
 
113
+ opts.on("", "MISC_OPTIONS")
114
+
138
115
  opts.on(
139
- "--rename=NAME",
140
- "Rename the current profile"
141
- ) do |name|
142
- options["action"] = "rename"
143
- options["rename"] = name
116
+ "--list-profile-names",
117
+ "List profile names for completion functions"
118
+ ) do
119
+ options["action"] = "list_profile_names"
144
120
  end
145
121
 
146
122
  opts.on(
147
- "-s",
148
- "--switch=NAME",
149
- "Switch to profile with specified name"
150
- ) do |name|
151
- options["action"] = "switch"
152
- options["use"] = name
123
+ "--list-tags",
124
+ "List tags for completion functions"
125
+ ) do
126
+ options["action"] = "list_tags"
127
+ end
128
+
129
+ opts.on("--nocolor", "Disable colorized output") do
130
+ Hilighter.disable
153
131
  end
154
132
 
155
133
  opts.on(
156
- "-u",
157
- "--use=NAME",
158
- "Use specified profile one time only"
159
- ) do |name|
160
- options["use"] = name
134
+ "-v",
135
+ "--verbose",
136
+ "Show backtrace when error occurs"
137
+ ) do
138
+ options["verbose"] = true
161
139
  end
162
140
 
163
- opts.on("-w", "--which", "Display the current profile") do
164
- options["action"] = "which"
141
+ opts.on("--version", "Show version") do
142
+ options["action"] = "version"
165
143
  end
166
144
 
167
- opts.on("", info.word_wrap(80))
145
+ opts.on(
146
+ "",
147
+ "EXAMPLES",
148
+ " Execute default profile:",
149
+ " $ z PATTERN",
150
+ "",
151
+ " Execute specified profile:",
152
+ " $ z -u grep PATTERN",
153
+ "",
154
+ " Pass additional flags to default profile:",
155
+ " $ z -- -A 3 PATTERN",
156
+ "",
157
+ " Open tags:",
158
+ " $ zg 10,20,30-40"
159
+ )
168
160
  end
169
161
 
170
162
  begin
@@ -181,13 +173,17 @@ def parse(args)
181
173
  puts e.message
182
174
  puts parser
183
175
  exit ZoomExit::MISSING_ARGUMENT
176
+ rescue OptionParser::AmbiguousOption => e
177
+ puts e.message
178
+ puts parser
179
+ exit ZoomExit::AMBIGUOUS_ARGUMENT
184
180
  end
185
181
 
186
182
  case File.basename($0)
187
183
  when "zc"
188
184
  options["action"] = "cache"
189
185
  when "zf"
190
- options["use"] = "zoom_find"
186
+ options["use"] = "find"
191
187
  when "zg"
192
188
  options["action"] = "go"
193
189
  options["use"] = args[0]
@@ -196,7 +192,7 @@ def parse(args)
196
192
  when "zr"
197
193
  options["action"] = "repeat"
198
194
  when "z"
199
- # do nothing, this is the normal usage
195
+ # Do nothing, this is the normal usage
200
196
  else
201
197
  options["use"] = File.basename($0)
202
198
  end
@@ -208,80 +204,126 @@ end
208
204
 
209
205
  options = parse(ARGV)
210
206
 
211
- zoom = Zoom.new(options["cache_file"])
212
207
  begin
208
+ if (options["action"] == "rc")
209
+ FileUtils.rm_f(Pathname.new("~/.zoomrc").expand_path)
210
+ end
211
+
212
+ zoom = Zoom.new(options["cache_file"], nil, !Hilighter.disable?)
213
+
213
214
  case options["action"]
214
- when "add"
215
- zoom.interactive_add_profile(options["use"])
216
215
  when "cache"
217
- zoom.shortcut_cache
218
- when "delete"
219
- zoom.delete_profile(options["use"])
220
- when "edit"
221
- zoom.interactive_edit_profile(options["use"])
222
- when "editor"
223
- zoom.configure_editor(options["use"])
224
- when "examples"
225
- puts [
226
- "EXAMPLES:",
227
- "",
228
- "Add a profile named test:",
229
- " $ z --add test",
230
- "",
231
- "Edit a profile named test:",
232
- " $ z --edit test",
233
- "",
234
- "Execute the current profile:",
235
- " $ z PATTERN",
236
- "",
237
- "Repeat the previous Zoom command:",
238
- " $ z --repeat",
239
- "",
240
- "Pass additional flags to the choosen operator:",
241
- " $ z -- -A 3 PATTERN",
242
- "",
243
- "Open a tag:",
244
- " $ z --go 10",
245
- "",
246
- "Open multiple tags:",
247
- " $ z --go 10,20,30-40"
248
- ].join("\n")
216
+ zoom.cache.shortcut(zoom.config)
217
+ when "configure"
218
+ Zoom.hilight(false)
219
+ djinni = Djinni.new
220
+ djinni.load_wishes(
221
+ "#{File.dirname(__FILE__)}/../lib/zoom/wish"
222
+ )
223
+ djinni.prompt(
224
+ {
225
+ "cache" => zoom.cache,
226
+ "config" => zoom.config,
227
+ "prompt_color" => "white",
228
+ "zoom" => zoom
229
+ },
230
+ "zoom(#{zoom.config.current_profile_name})> ".white
231
+ )
249
232
  when "go"
250
- zoom.loop_through_results(options["use"])
233
+ if (options["use"])
234
+ results = zoom.cache.get_results(options["use"])
235
+ zoom.open(results)
236
+ end
251
237
  when "list_profiles"
252
- zoom.list_profiles
238
+ profiles = zoom.config.get_profiles
239
+ profiles.keys.sort do |a, b|
240
+ a.downcase <=> b.downcase
241
+ end.each do |name|
242
+ if (name == zoom.config.current_profile_name)
243
+ print "*".red if (Zoom.hilight?)
244
+ print "*" if (!Zoom.hilight?)
245
+ end
246
+
247
+ lines = profiles[name].to_s.scan(
248
+ /\S.{0,76}\S(?=\s|$)|\S+/
249
+ )
250
+ puts lines.delete_at(0)
251
+ lines.each do |line|
252
+ puts " #{line}"
253
+ end
254
+ end
253
255
  when "list_profile_names"
254
- zoom.list_profile_names
256
+ puts zoom.config.get_profile_names
255
257
  when "list_tags"
256
- zoom.list_tags
257
- when "pager"
258
- zoom.pager
258
+ puts zoom.cache.available_tags
259
259
  when "repeat"
260
260
  zoom.repeat
261
261
  when "rc"
262
- zoom.default
263
- when "rename"
264
- zoom.rename_profile(
265
- options["rename"],
266
- options["use"]
267
- )
268
- when "switch"
269
- zoom.switch_profile(options["use"])
262
+ zoom.config.default_config
263
+ zoom.cache.clear
264
+ when "version"
265
+ __FILE__.match(/ruby-zoom-(\d+\.\d+\.\d+)/) do |m|
266
+ puts m[1]
267
+ end
270
268
  when "which"
271
- zoom.show_current
269
+ name = zoom.config.current_profile_name
270
+ profile = zoom.config.get_profiles[name]
271
+
272
+ print "*".red if (Zoom.hilight?)
273
+ print "*" if (!Zoom.hilight?)
274
+
275
+ lines = profile.to_s.scan(/\S.{0,76}\S(?=\s|$)|\S+/)
276
+ puts lines.delete_at(0)
277
+ lines.each do |line|
278
+ puts " #{line}"
279
+ end
272
280
  else
273
- # Search and save results
274
- zoom.exec_profile(
281
+ # Search and cache results
282
+ zoom.run(
275
283
  options["use"],
276
284
  options["subargs"],
277
285
  options["pattern"]
278
286
  )
279
287
  end
288
+ rescue SystemExit
289
+ # Quit from djinni
290
+ # Exit gracefully
280
291
  rescue Zoom::Error => e
281
- puts e.message
292
+ $stderr.puts e.message
293
+ if (options["verbose"])
294
+ e.backtrace.each do |line|
295
+ $stderr.puts line.yellow
296
+ end
297
+ end
282
298
  exit ZoomExit::EXCEPTION
299
+ rescue Interrupt
300
+ # ^C
301
+ # Exit gracefully
302
+ rescue Errno::EPIPE
303
+ # Do nothing. This can happen if piping to another program such as
304
+ # less. Usually if less is closed before Zoom is done with STDOUT.
283
305
  rescue Exception => e
284
- puts e.message
306
+ $stderr.puts
307
+ $stderr.puts "Oops! Looks like an error has occured! Try " \
308
+ "resetting your configs with the"
309
+ $stderr.puts "following comand:"
310
+ $stderr.puts
311
+ $stderr.puts " z --rc"
312
+ $stderr.puts
313
+ $stderr.puts "If the error persists, file a bug at:"
314
+ $stderr.puts
315
+ $stderr.puts " https://gitlab.com/mjwhitta/zoom/issues"
316
+ $stderr.puts
317
+ $stderr.puts "Maybe the message below will help. If not, you " \
318
+ "can use the --verbose flag to get"
319
+ $stderr.puts "a backtrace."
320
+
321
+ $stderr.puts e.message.white.on_red
322
+ if (options["verbose"])
323
+ e.backtrace.each do |line|
324
+ $stderr.puts line.yellow
325
+ end
326
+ end
285
327
  exit ZoomExit::EXCEPTION
286
328
  end
287
329
  exit ZoomExit::GOOD
@@ -1,637 +1,81 @@
1
- require "io/wait"
2
- require "json"
3
1
  require "pathname"
4
- require "string"
5
2
 
6
3
  class Zoom
7
- def add_profile(
8
- name,
9
- clas,
10
- operator = nil,
11
- flags = nil,
12
- envprepend = nil,
13
- append = nil
14
- )
15
- if (@profiles.has_key?(name))
16
- raise Zoom::Error::ProfileAlreadyExistsError.new(name)
17
- end
18
-
19
- default_class = nil
20
- begin
21
- default_class = Zoom::Profile.profile_by_name(clas).new
22
- rescue NameError => e
23
- raise Zoom::Error::ProfileClassUnknownError.new(clas)
24
- end
4
+ attr_reader :cache
5
+ attr_reader :config
25
6
 
26
- edit_profile(
27
- name,
28
- default_class,
29
- operator,
30
- flags,
31
- envprepend,
32
- append
33
- )
7
+ def self.hilight(hilight = true)
8
+ @@hilight = hilight
34
9
  end
35
10
 
36
- def clear_cache
37
- @cache_file.delete if (@cache_file.exist?)
11
+ def self.hilight?
12
+ @@hilight ||= false
13
+ return @@hilight
38
14
  end
39
15
 
40
- def configure_editor(editor)
41
- e = ScoobyDoo.where_are_you(editor)
42
- if (e.nil?)
43
- raise Zoom::Error::ExecutableNotFoundError.new(editor)
44
- end
16
+ def initialize(cache = nil, rc = nil, hilight = false)
17
+ @@hilight = hilight
18
+ @cache = Zoom::Cache.new(cache)
19
+ @config = Zoom::Config.new(rc)
45
20
 
46
- @rc["editor"] = e
47
- write_zoomrc
21
+ # Prioritize false, so only reassign if true
22
+ @@hilight = @config.hilight if (hilight)
48
23
  end
49
24
 
50
- def default
51
- default_zoominfo
52
- default_zoomrc
53
- end
54
-
55
- def default_zoominfo
56
- info = Hash.new
57
- info["profile"] = "default"
58
-
59
- # Reset last command to be empty
60
- info["last_command"] = Hash.new
25
+ def open(results)
26
+ return if (results.nil? || results.empty?)
61
27
 
62
- File.open(@info_file, "w") do |file|
63
- file.write(JSON.pretty_generate(info))
64
- end
28
+ # All results should be from the same profile
29
+ profile = @config.get_profile(results[0].profile_name)
30
+ profile.go(@config.editor, results)
65
31
  end
66
32
 
67
- def default_zoomrc
68
- rc = Hash.new
69
- profiles = Hash.new
70
-
71
- all = nil
72
- ag = nil
73
- pt = nil
74
- ack = nil
75
-
76
- # Default ag profiles
77
- if (ScoobyDoo.where_are_you("ag"))
78
- ag = Zoom::Profile::Ag.new
79
- all = Zoom::Profile::Ag.new(nil, "-u")
80
- end
81
-
82
- # Default pt profiles
83
- if (ScoobyDoo.where_are_you("pt"))
84
- pt = Zoom::Profile::Pt.new
85
- all ||= Zoom::Profile::Pt.new(nil, "--color -SeU")
86
- end
33
+ def repeat
34
+ return if (@cache.empty?)
87
35
 
88
- # Default ack profile
89
- if (
90
- ScoobyDoo.where_are_you("ack") ||
91
- ScoobyDoo.where_are_you("ack-grep")
36
+ run(
37
+ @cache.profile_name,
38
+ @cache.args,
39
+ @cache.pattern
92
40
  )
93
- ack = Zoom::Profile::Ack.new
94
- end
95
-
96
- # Default grep profile (emulate ag/ack as much as possible)
97
- grep = Zoom::Profile::Grep.new
98
- all ||= Zoom::Profile::Grep.new(nil, "--color=always -EHinR")
99
-
100
- # Create default profile
101
- if (ag)
102
- default = ag
103
- elsif (pt)
104
- default = pt
105
- elsif (ack)
106
- default = ack
107
- else
108
- default = grep
109
- end
110
-
111
- # Create find profile
112
- find = Zoom::Profile::Find.new
113
-
114
- # Put profiles into rc
115
- profiles["ack"] = ack if (ack)
116
- profiles["ag"] = ag if (ag)
117
- profiles["all"] = all if (all)
118
- profiles["default"] = default
119
- profiles["grep"] = grep
120
- profiles["passwords"] = Zoom::Profile::Passwords.new
121
- profiles["pt"] = pt if (pt)
122
- profiles["zoom_find"] = find
123
- rc["profiles"] = profiles
124
-
125
- # Default editor (use $EDITOR)
126
- rc["editor"] = ""
127
-
128
- File.open(@rc_file, "w") do |file|
129
- file.write(JSON.pretty_generate(rc))
130
- end
131
- end
132
-
133
- def delete_profile(name)
134
- if (!@profiles.has_key?(name))
135
- raise Zoom::Error::ProfileDoesNotExistError.new(name)
136
- end
137
-
138
- if ((name == "default") || @profiles[name].immutable)
139
- raise Zoom::Error::ProfileCanNotBeModifiedError.new(name)
140
- end
141
-
142
- @profiles.delete(name)
143
- write_zoomrc
144
-
145
- if (name == @info["profile"])
146
- @info["profile"] = "default"
147
- write_zoominfo
148
- end
149
41
  end
150
42
 
151
- def edit_profile(
152
- name,
153
- profile = nil,
154
- operator = nil,
155
- flags = nil,
156
- envprepend = nil,
157
- append = nil
158
- )
159
- profile = @profiles[name] if (profile.nil?)
43
+ def run(prof_name, args, pattern)
44
+ prof_name = @config.current_profile_name if (prof_name.nil?)
160
45
 
161
- if (profile.nil?)
162
- raise Zoom::Error::ProfileDoesNotExistsError.new(name)
46
+ if (!@config.has_profile?(prof_name))
47
+ raise Zoom::Error::ProfileDoesNotExist.new(prof_name)
163
48
  end
164
49
 
165
- if (profile.immutable)
166
- raise Zoom::Error::ProfileCanNotBeModifiedError.new(name)
167
- end
168
-
169
- profile.operator(operator) if (operator)
170
- profile.flags(flags) if (flags)
171
- profile.prepend(envprepend) if (envprepend)
172
- profile.append(append) if (append)
173
-
174
- @profiles[name] = profile
175
- write_zoomrc
176
- end
177
-
178
- def exec_profile(name, args, pattern)
179
- name = @info["profile"] if (name.nil?)
180
-
181
- if (!@profiles.has_key?(name))
182
- raise Zoom::Error::ProfileDoesNotExistError.new(name)
183
- end
184
-
185
- @info["last_command"] = {
186
- "profile" => name,
187
- "subargs" => args.nil? ? "": args,
188
- "pattern" => pattern.nil? ? "" : pattern
189
- }
190
- write_zoominfo
191
-
192
- profile = @profiles[name]
50
+ profile = @config.get_profile(prof_name)
193
51
  begin
194
- clear_cache if (profile.taggable)
195
- profile.exe(args, pattern)
196
- shortcut_cache(profile) if (profile.taggable)
197
- rescue Interrupt
198
- # ^C
199
- end
200
- end
201
-
202
- def get_location_of_result(result)
203
- count = 0
204
- File.open(@shortcut_file) do |file|
205
- file.each do |line|
206
- count += 1
207
- if (count == result)
208
- return line
209
- end
210
- end
211
- end
212
- return nil
213
- end
214
- private :get_location_of_result
215
-
216
- def get_new_value(val, default)
217
- return default if (val.nil? || val.empty?)
218
- return "" if (val.downcase == "empty")
219
- return "" if (val.downcase == "\"empty\"")
220
- return val
221
- end
222
- private :get_new_value
223
-
224
- def initialize(cache_file = nil)
225
- cache_file ||= "~/.zoom_cache"
226
- Zoom::Profile.cache_file(cache_file)
227
- @cache_file = Pathname.new(cache_file).expand_path
228
- @info_file = Pathname.new("~/.zoominfo").expand_path
229
- @rc_file = Pathname.new("~/.zoomrc").expand_path
230
- @shortcut_file = Pathname.new("~/.zoom_shortcuts").expand_path
231
-
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
- read_zoomrc
237
- read_zoominfo
238
-
239
- # Setup editor
240
- @editor = @rc["editor"]
241
- @editor = ENV["EDITOR"] if (@editor.nil? || @editor.empty?)
242
- @editor = "vim" if (@editor.nil? || @editor.empty?)
243
- @editor = ScoobyDoo.where_are_you(@editor)
244
- @editor = ScoobyDoo.where_are_you("vi") if (@editor.nil?)
245
-
246
- end
247
-
248
- def interactive_add_profile(name)
249
- if (@profiles.has_key?(name))
250
- raise Zoom::Error::ProfileAlreadyExistsError.new(name)
251
- end
252
-
253
- default_op = "grep"
254
- if (ScoobyDoo.where_are_you("ag"))
255
- default_op = "ag"
256
- elsif (ScoobyDoo.where_are_you("pt"))
257
- default_op = "pt"
258
- elsif (ScoobyDoo.where_are_you("ack"))
259
- default_op = "ack"
260
- elsif (ScoobyDoo.where_are_you("ack-grep"))
261
- default_op = "ack-grep"
262
- end
263
-
264
- ack_class = Zoom::Profile::Ack.to_s
265
- ag_class = Zoom::Profile::Ag.to_s
266
- grep_class = Zoom::Profile::Grep.to_s
267
- pt_class = Zoom::Profile::Pt.to_s
268
-
269
- case default_op
270
- when "ack", "ack-grep"
271
- puts "Enter class (default #{ack_class}):"
272
- when "ag"
273
- puts "Enter class (default #{ag_class}):"
274
- when "grep"
275
- puts "Enter class (default #{grep_class}):"
276
- when "pt"
277
- puts "Enter class (default #{pt_class}):"
278
- end
52
+ @cache.clear
279
53
 
280
- clas = gets.chomp
281
- puts if (clas && !clas.empty?)
282
-
283
- case default_op
284
- when "ack", "ack-grep"
285
- clas = ack_class if (clas.nil? || clas.empty?)
286
- when "ag"
287
- clas = ag_class if (clas.nil? || clas.empty?)
288
- when "grep"
289
- clas = grep_class if (clas.nil? || clas.empty?)
290
- when "pt"
291
- clas = pt_class if (clas.nil? || clas.empty?)
292
- end
293
-
294
- add_profile(name, clas)
295
- interactive_edit_profile(name)
296
- end
297
-
298
- def interactive_edit_profile(name, profile = nil)
299
- profile = @profiles[name] if (profile.nil?)
300
-
301
- if (profile.nil?)
302
- raise Zoom::Error::ProfileDoesNotExistError.new(name)
303
- end
304
-
305
- if (profile.immutable)
306
- raise Zoom::Error::ProfileCanNotBeModifiedError.new(name)
307
- end
308
-
309
- # Get new operator
310
- puts "Enter operator (default #{profile.operator}):"
311
-
312
- op = ScoobyDoo.where_are_you(gets.chomp)
313
- puts if (op && !op.empty?)
314
- op = profile.operator if (op.nil? || op.empty?)
315
-
316
- # Get new flags
317
- puts "For empty string put \"empty\""
318
- puts "Enter flags (default \"#{profile.flags}\"):"
319
-
320
- flags = gets.chomp
321
- puts if (flags && !flags.empty?)
322
- flags = get_new_value(flags, profile.flags)
323
-
324
- # Get new prepend
325
- puts "For empty string put \"empty\""
326
- puts "Enter prepend (default \"#{profile.prepend}\"):"
327
-
328
- envprepend = gets.chomp
329
- puts if (envprepend && !envprepend.empty?)
330
- envprepend = get_new_value(envprepend, profile.prepend)
331
-
332
- # Get new append
333
- puts "For empty string put \"empty\""
334
- puts "Enter append (default \"#{profile.append}\"):"
335
-
336
- append = gets.chomp
337
- puts if (append && !append.empty?)
338
- append = get_new_value(append, profile.append)
339
-
340
- edit_profile(name, profile, op, flags, envprepend, append)
341
- end
342
-
343
- def list_profile_names
344
- @profiles.keys.sort.each do |name|
345
- puts name
346
- end
347
- end
348
-
349
- def list_profiles
350
- @profiles.keys.sort.each do |name|
351
- if (name == @info["profile"])
352
- puts "### #{name} ###".green
353
- else
354
- puts "### #{name} ###"
355
- end
356
- puts @profiles[name].info
357
- puts
358
- end
359
- end
360
-
361
- def list_tags
362
- return if (!@cache_file.exist?)
363
-
364
- # Open shortcut file for writing
365
- shct = File.open(@shortcut_file, "r")
366
-
367
- # Read in cache
368
- File.open(@cache_file) do |cache|
369
- count = 1
370
-
371
- cache.each do |line|
372
- line.chomp!
373
- plain = remove_colors(line)
374
- if (line.start_with?("ZOOM_EXE_DIR="))
375
- # Ignore this line
376
- elsif ((line == "-") || (line == "--") || line.empty?)
377
- # Ignore dividers when searching with context and
378
- # empty lines
379
- elsif (plain.scan(/^[0-9]+[:-]/).empty?)
380
- if (!plain.scan(/^\.\//).empty?)
381
- # Operator was probably find
382
- puts count
383
- count += 1
384
- end
385
- else
386
- puts count
387
- count += 1
388
- end
389
- end
390
- end
391
- end
392
-
393
- def loop_through_results(results)
394
- tags = parse_tags(results)
395
- return if (tags.empty?)
396
-
397
- tag = tags.delete_at(0)
398
- open_editor_to_result(tag)
399
-
400
- tags.each do |tag|
401
- print "Do you want to open result #{tag} [y]/n/q/l?: "
402
-
403
- answer = nil
404
- while (answer.nil?)
405
- begin
406
- system("stty raw -echo")
407
- if ($stdin.ready?)
408
- answer = $stdin.getc
409
- else
410
- sleep 0.1
411
- end
412
- ensure
413
- system("stty -raw echo")
414
- end
415
- end
416
- puts
417
-
418
- case answer
419
- when "n", "N"
420
- # Do nothing
421
- when "l", "L"
422
- # Open this result then exit
423
- open_editor_to_result(tag)
424
- return
425
- when "q", "Q", "\x03"
426
- # Quit or ^C
427
- return
54
+ # Store needed details
55
+ if (pattern && profile.pattern.empty?)
56
+ @cache.args(args)
57
+ @cache.pattern(pattern)
428
58
  else
429
- open_editor_to_result(tag)
59
+ @cache.args("")
60
+ @cache.pattern(profile.pattern)
430
61
  end
431
- end
432
- end
62
+ @cache.profile_name(prof_name)
63
+ @cache.pwd(Dir.pwd)
433
64
 
434
- def open_editor_to_result(result)
435
- loc = get_location_of_result(result.to_i)
436
- if (loc)
437
- system("#{@editor} #{loc}")
438
- else
439
- puts "Invalid tag \"#{result}\"!"
440
- end
441
- end
442
- private :open_editor_to_result
443
-
444
- def pager
445
- File.open(@cache_file, "w") do |f|
446
- f.write("ZOOM_EXE_DIR=#{Dir.pwd}\n")
447
- begin
448
- $stdin.each_line do |line|
449
- f.write(line)
450
- end
451
- rescue Interrupt
452
- # ^C
453
- end
454
- end
455
- end
456
-
457
- def parse_tags(results)
458
- tags = Array.new
459
- if (results.nil? || results.empty?)
460
- raise Zoom::Error::InvalidTagError.new
461
- end
462
-
463
- results.split(",").each do |num|
464
- if (!num.scan(/^[0-9]+$/).empty?)
465
- tags.push(num.to_i)
466
- elsif (!num.scan(/^[0-9]+-[0-9]+$/).empty?)
467
- range = num.split("-")
468
- (range[0].to_i..range[1].to_i).each do |i|
469
- tags.push(i)
470
- end
471
- else
472
- raise Zoom::Error::InvalidTagError.new(num)
473
- end
474
- end
475
- return tags
476
- end
477
- private :parse_tags
478
-
479
- def read_zoominfo
480
- if (!@info_file.exist? && !@info_file.symlink?)
481
- default_zoominfo
482
- end
483
-
484
- @info = JSON.parse(File.read(@info_file))
485
- end
486
- private :read_zoominfo
487
-
488
- def read_zoomrc
489
- if (!@rc_file.exist? && !@rc_file.symlink?)
490
- default_zoomrc
491
- end
492
-
493
- @rc = JSON.parse(File.read(@rc_file))
494
- @profiles = Hash.new
495
- @rc["profiles"].each do |name, prof|
496
- @profiles[name] = Zoom::Profile.from_json(prof)
497
- end
498
- @rc["profiles"] = @profiles
499
- end
500
- private :read_zoomrc
65
+ # Execute profile
66
+ @cache.write(profile.exe(args, pattern))
501
67
 
502
- def rename_profile(rename, name = nil)
503
- name = @info["profile"] if (name.nil?)
504
-
505
- if ((name == "default") || (name == "zoom_find"))
506
- raise Zoom::Error::ProfileCanNotBeModifiedError.new(name)
507
- end
508
-
509
- if (!@profiles.has_key?(name))
510
- raise Zoom::Error::ProfileDoesNotExistError.new(name)
511
- end
512
-
513
- if (@profiles.has_key?(rename))
514
- raise Zoom::Error::ProfileAlreadyExistsError.new(rename)
515
- end
516
-
517
- @profiles[rename] = @profiles[name]
518
- @profiles.delete(name)
519
- write_zoomrc
520
-
521
- if (name == @info["profile"])
522
- @info["profile"] = rename
523
- write_zoominfo
524
- end
525
- end
526
-
527
- def repeat
528
- return if (@info["last_command"].empty?)
529
-
530
- exec_profile(
531
- @info["last_command"]["profile"],
532
- @info["last_command"]["subargs"],
533
- @info["last_command"]["pattern"]
534
- )
535
- end
536
-
537
- def remove_colors(str)
538
- str.unpack("C*").pack("U*").gsub(/\e\[([0-9;]*m|K)/, "")
539
- end
540
- private :remove_colors
541
-
542
- def shortcut_cache(profile = nil)
543
- return if (!@cache_file.exist?)
544
- return if (@info["last_command"].empty?)
545
-
546
- if (profile.nil?)
547
- profile = @profiles[@info["last_command"]["profile"]]
548
- end
549
-
550
- # Open shortcut file for writing
551
- shct = File.open(@shortcut_file, "w")
552
-
553
- # Read in cache
554
- File.open(@cache_file) do |cache|
555
- start_dir = ""
556
- file = nil
557
- filename = ""
558
- first_time = true
559
- count = 1
560
-
561
- cache.each do |line|
562
- line.chomp!
563
- plain = remove_colors(line)
564
- if (line.start_with?("ZOOM_EXE_DIR="))
565
- # Get directory where search was ran
566
- start_dir = line.gsub("ZOOM_EXE_DIR=", "")
567
- elsif ((line == "-") || (line == "--") || line.empty?)
568
- # Ignore dividers when searching with context and
569
- # empty lines
570
- elsif (plain.scan(/^[0-9]+[:-]/).empty?)
571
- operator = profile.operator.split("/").last
572
- if (operator != "find")
573
- if (file != line)
574
- # Filename
575
- file = line
576
- filename = remove_colors(file)
577
-
578
- puts if (!first_time)
579
- first_time = false
580
-
581
- puts "\e[0m#{file}"
582
- end
583
- else
584
- # Operator was find
585
- puts "\e[1;31m[#{count}]\e[0m #{line}"
586
- shct.write("'#{start_dir}/#{line}'\n")
587
- count += 1
588
- end
589
- elsif (file)
590
- # Match
591
- sanitized = line.unpack("C*").pack("U*")
592
- .gsub(/[\u0080-\u00ff]+/, "\1".dump[1..-2])
593
- puts "\e[1;31m[#{count}]\e[0m #{sanitized}"
594
-
595
- lineno = remove_colors(line).split(/[:-]/)[0]
596
- shct.write(
597
- "+#{lineno} '#{start_dir}/#{filename}'\n"
598
- )
599
-
600
- count += 1
601
- end
602
- end
603
- end
604
- end
605
-
606
- def show_current
607
- puts "### #{@info["profile"]} ###".green
608
- puts @profiles[@info["profile"]].info
609
- end
610
-
611
- def switch_profile(name)
612
- if (!@profiles.has_key?(name))
613
- raise Zoom::Error::ProfileDoesNotExistError.new(name)
614
- end
615
-
616
- @info["profile"] = name
617
- write_zoominfo
618
- end
619
-
620
- def write_zoominfo
621
- File.open(@info_file, "w") do |file|
622
- file.write(JSON.pretty_generate(@info))
623
- end
624
- end
625
- private :write_zoominfo
626
-
627
- def write_zoomrc
628
- @rc["profiles"] = @profiles
629
- File.open(@rc_file, "w") do |file|
630
- file.write(JSON.pretty_generate(@rc))
68
+ # Display results from cache
69
+ @cache.shortcut(@config)
70
+ rescue Interrupt
71
+ # ^C
631
72
  end
632
73
  end
633
- private :write_zoomrc
634
74
  end
635
75
 
76
+ require "zoom/cache"
77
+ require "zoom/config"
78
+ require "zoom/editor"
636
79
  require "zoom/error"
637
80
  require "zoom/profile"
81
+ require "zoom/profile_manager"