ruby-zoom 4.7.5 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/z +108 -50
- data/bin/zc +108 -50
- data/bin/zf +108 -50
- data/bin/zg +108 -50
- data/bin/zl +108 -50
- data/bin/zr +108 -50
- data/lib/zoom.rb +89 -26
- data/lib/zoom/cache.rb +10 -9
- data/lib/zoom/cache/result.rb +3 -3
- data/lib/zoom/config.rb +15 -6
- data/lib/zoom/editor.rb +8 -4
- data/lib/zoom/error.rb +1 -0
- data/lib/zoom/error/regex_not_provided.rb +5 -0
- data/lib/zoom/profile.rb +62 -90
- data/lib/zoom/profile/ack.rb +35 -10
- data/lib/zoom/profile/ag.rb +21 -5
- data/lib/zoom/profile/find.rb +48 -4
- data/lib/zoom/profile/grep.rb +25 -5
- data/lib/zoom/profile/passwords.rb +5 -13
- data/lib/zoom/profile/pt.rb +21 -5
- data/lib/zoom/profile/rg.rb +51 -0
- data/lib/zoom/profile/unsafe_c.rb +32 -30
- data/lib/zoom/profile/unsafe_java.rb +15 -28
- data/lib/zoom/profile/unsafe_js.rb +5 -12
- data/lib/zoom/profile/unsafe_php.rb +48 -55
- data/lib/zoom/profile/unsafe_python.rb +16 -24
- data/lib/zoom/profile/unsafe_ruby.rb +16 -25
- data/lib/zoom/profile_manager.rb +50 -16
- data/lib/zoom/security_profile.rb +60 -5
- data/lib/zoom/wish/edit_wish.rb +4 -4
- data/lib/zoom/wish/editor_wish.rb +2 -8
- metadata +14 -12
data/lib/zoom.rb
CHANGED
@@ -5,6 +5,77 @@ class Zoom
|
|
5
5
|
attr_reader :cache
|
6
6
|
attr_reader :config
|
7
7
|
|
8
|
+
def ensure_valid_header(header)
|
9
|
+
# Ensure header has no nil
|
10
|
+
header["args"] ||= ""
|
11
|
+
header["debug"] ||= false
|
12
|
+
header["paths"] ||= "."
|
13
|
+
header["paths"] = "." if (header["paths"].empty?)
|
14
|
+
header["profile_name"] ||= ""
|
15
|
+
header["pwd"] = Dir.pwd
|
16
|
+
header["regex"] ||= ""
|
17
|
+
header["translate"] ||= Hash.new
|
18
|
+
|
19
|
+
# If no profile name, use the current profile
|
20
|
+
profile_name = header["profile_name"]
|
21
|
+
if (profile_name.empty?)
|
22
|
+
profile_name = @config.current_profile_name
|
23
|
+
header["profile_name"] = profile_name
|
24
|
+
end
|
25
|
+
|
26
|
+
if (!@config.has_profile?(profile_name))
|
27
|
+
raise Zoom::Error::ProfileDoesNotExist.new(profile_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
profile = @config.get_profile(profile_name)
|
31
|
+
|
32
|
+
# Use hard-coded regex if defined
|
33
|
+
if (
|
34
|
+
profile.regex &&
|
35
|
+
!profile.regex.empty? &&
|
36
|
+
(header["regex"] != profile.regex)
|
37
|
+
)
|
38
|
+
# If there was a regex then it may be an arg or a path
|
39
|
+
if (!header["regex"].empty?)
|
40
|
+
if (Pathname.new(header["regex"]).exist?)
|
41
|
+
header["paths"] = "" if (header["paths"] == ".")
|
42
|
+
paths = header["paths"].split(" ")
|
43
|
+
paths.insert(0, header["regex"])
|
44
|
+
header["paths"] = paths.join(" ")
|
45
|
+
else
|
46
|
+
header["args"] += " #{header["regex"]}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
header["regex"] = profile.regex
|
51
|
+
end
|
52
|
+
|
53
|
+
# If using a search tool
|
54
|
+
if (!profile.format_flags.empty?)
|
55
|
+
if (header["regex"].empty? && header["paths"] == ".")
|
56
|
+
# Throw exception because no regex was provided or
|
57
|
+
# hard-coded
|
58
|
+
raise Zoom::Error::RegexNotProvided.new
|
59
|
+
end
|
60
|
+
|
61
|
+
# This isn't done here anymore as it breaks stuff
|
62
|
+
# header["regex"] = header["regex"].shellescape
|
63
|
+
end
|
64
|
+
|
65
|
+
# Strip values
|
66
|
+
header.keys.each do |key|
|
67
|
+
next if (key == "regex")
|
68
|
+
begin
|
69
|
+
header[key].strip!
|
70
|
+
rescue
|
71
|
+
# Wasn't a String
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
return header
|
76
|
+
end
|
77
|
+
private :ensure_valid_header
|
78
|
+
|
8
79
|
def self.hilight(hilight = true)
|
9
80
|
@@hilight = hilight
|
10
81
|
end
|
@@ -22,10 +93,7 @@ class Zoom
|
|
22
93
|
|
23
94
|
def open(results)
|
24
95
|
return if (results.nil? || results.empty?)
|
25
|
-
|
26
|
-
# All results should be from the same profile
|
27
|
-
profile = @config.get_profile(results[0].profile_name)
|
28
|
-
profile.go(@config.editor, results)
|
96
|
+
Zoom::Editor.new(@config.editor).open(results)
|
29
97
|
end
|
30
98
|
|
31
99
|
def repeat(shortcut = true)
|
@@ -33,39 +101,34 @@ class Zoom
|
|
33
101
|
run(@cache.header, shortcut, true)
|
34
102
|
end
|
35
103
|
|
36
|
-
def run(
|
37
|
-
#
|
38
|
-
|
39
|
-
header[key] ||= ""
|
40
|
-
end
|
41
|
-
header["paths"] ||= "."
|
42
|
-
header["pwd"] = Dir.pwd
|
43
|
-
header["translate"] ||= Array.new
|
44
|
-
|
45
|
-
profile_name = header["profile_name"]
|
46
|
-
if (profile_name.empty?)
|
47
|
-
profile_name = @config.current_profile_name
|
48
|
-
header["profile_name"] = profile_name
|
49
|
-
end
|
104
|
+
def run(h, shortcut = true, repeat = false)
|
105
|
+
# Don't change the header passed in
|
106
|
+
header = h.clone
|
50
107
|
|
51
|
-
|
52
|
-
|
53
|
-
end
|
108
|
+
# Ensure header is formatted properly and valid
|
109
|
+
header = ensure_valid_header(header) if (!repeat)
|
54
110
|
|
111
|
+
profile_name = header["profile_name"]
|
55
112
|
profile = @config.get_profile(profile_name)
|
56
|
-
begin
|
57
|
-
# This will translate and/or append args such that the
|
58
|
-
# output will be something Zoom can process
|
59
|
-
header = profile.preprocess(header) if (!repeat)
|
60
113
|
|
114
|
+
begin
|
61
115
|
# Clear cache
|
62
116
|
@cache.clear
|
63
117
|
|
64
118
|
# Store needed details
|
65
119
|
@cache.header(header)
|
66
120
|
|
121
|
+
# Translate any needed flags
|
122
|
+
header["translated"] = profile.translate(
|
123
|
+
header["translate"]
|
124
|
+
).strip
|
125
|
+
|
126
|
+
# This may append args such that the output will be
|
127
|
+
# something Zoom can process
|
128
|
+
header = profile.preprocess(header)
|
129
|
+
|
67
130
|
# Execute profile
|
68
|
-
@cache.write(profile.exe(header), header["
|
131
|
+
@cache.write(profile.exe(header), header["regex"])
|
69
132
|
|
70
133
|
# Display results from cache
|
71
134
|
@cache.shortcut(@config) if (shortcut)
|
data/lib/zoom/cache.rb
CHANGED
@@ -111,11 +111,6 @@ class Zoom::Cache
|
|
111
111
|
return @header["paths"]
|
112
112
|
end
|
113
113
|
|
114
|
-
def pattern
|
115
|
-
return nil if (@header.nil?)
|
116
|
-
return @header["pattern"]
|
117
|
-
end
|
118
|
-
|
119
114
|
def profile_name
|
120
115
|
return nil if (@header.nil?)
|
121
116
|
return @header["profile_name"]
|
@@ -155,6 +150,11 @@ class Zoom::Cache
|
|
155
150
|
end
|
156
151
|
end
|
157
152
|
|
153
|
+
def regex
|
154
|
+
return nil if (@header.nil?)
|
155
|
+
return @header["regex"]
|
156
|
+
end
|
157
|
+
|
158
158
|
def shortcut(config)
|
159
159
|
return if (empty?)
|
160
160
|
|
@@ -184,7 +184,7 @@ class Zoom::Cache
|
|
184
184
|
config.hilight_tag("[#{result.tag}]"),
|
185
185
|
"#{config.hilight_lineno(result.lineno)}:",
|
186
186
|
result.match.gsub(
|
187
|
-
/(#{
|
187
|
+
/(#{regex})/i,
|
188
188
|
config.hilight_match("\\1")
|
189
189
|
)
|
190
190
|
].join(" ")
|
@@ -204,7 +204,7 @@ class Zoom::Cache
|
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
-
def write(str,
|
207
|
+
def write(str, r = nil)
|
208
208
|
return if (str.nil?)
|
209
209
|
|
210
210
|
if (!str.valid_encoding?)
|
@@ -217,15 +217,16 @@ class Zoom::Cache
|
|
217
217
|
|
218
218
|
File.open(@cache_file, "a") do |f|
|
219
219
|
str.gsub(/\r/, "^M").split("\n").each do |line|
|
220
|
-
if (
|
220
|
+
if (r && line.match(/^[^:]+:[0-9]+:.+$/))
|
221
221
|
line.match(/^([^:]+:[0-9]+:)(.+)$/) do |m|
|
222
222
|
m[2].scan(
|
223
|
-
/(.{0,128}#{
|
223
|
+
/(.{0,128}#{r}.{0,128})/i
|
224
224
|
) do |n|
|
225
225
|
f.write("#{m[1]}#{n[0]}\n")
|
226
226
|
end
|
227
227
|
end
|
228
228
|
else
|
229
|
+
line.gsub!(/^(.{128}).*(.{128})$/, "\\1...\\2")
|
229
230
|
f.write("#{line}\n")
|
230
231
|
end
|
231
232
|
end
|
data/lib/zoom/cache/result.rb
CHANGED
@@ -28,12 +28,12 @@ class Zoom::Cache::Result
|
|
28
28
|
@filename = "Binary file"
|
29
29
|
@contents = m[1]
|
30
30
|
end
|
31
|
-
when /^([^:]+)
|
32
|
-
@contents.match(/^([^:]+)
|
31
|
+
when /^([^:]+)[:-](\d+)[:-](.*)$/
|
32
|
+
@contents.match(/^([^:]+)[:-](\d+)[:-](.*)$/) do |m|
|
33
33
|
next if (m.nil?)
|
34
34
|
|
35
35
|
@grep_like = true
|
36
|
-
@filename = m[1]
|
36
|
+
@filename = m[1].gsub(/^\.\//, "")
|
37
37
|
@lineno = m[2]
|
38
38
|
@match = m[3]
|
39
39
|
end
|
data/lib/zoom/config.rb
CHANGED
@@ -49,7 +49,7 @@ class Zoom::Config < JSONConfig
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def default_config
|
52
|
-
default = Zoom::ProfileManager.
|
52
|
+
default = Zoom::ProfileManager.default_tool
|
53
53
|
profiles = Zoom::ProfileManager.default_profiles
|
54
54
|
|
55
55
|
clear
|
@@ -64,20 +64,29 @@ class Zoom::Config < JSONConfig
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def editor(ed = nil)
|
67
|
-
if (ed)
|
68
|
-
e =
|
69
|
-
|
67
|
+
if (ed && !ed.empty?)
|
68
|
+
e = ed.split(" ")[0]
|
69
|
+
if (ScoobyDoo.where_are_you(e).nil?)
|
70
|
+
raise Zoom::Error::ExecutableNotFound.new(e)
|
71
|
+
end
|
70
72
|
set("editor", ed)
|
71
73
|
end
|
72
74
|
|
73
75
|
e = get("editor")
|
74
76
|
e = ENV["EDITOR"] if (e.nil? || e.empty?)
|
75
77
|
e = "vim" if (e.nil? || e.empty?)
|
78
|
+
|
79
|
+
e, _, f = e.partition(" ")
|
76
80
|
e = ScoobyDoo.where_are_you(e)
|
77
|
-
|
81
|
+
|
82
|
+
if (e.nil?)
|
83
|
+
e = ScoobyDoo.where_are_you("vi")
|
84
|
+
f = ""
|
85
|
+
end
|
86
|
+
|
78
87
|
raise Zoom::Error::ExecutableNotFound.new("vi") if (e.nil?)
|
79
88
|
|
80
|
-
return e
|
89
|
+
return "#{e} #{f}".strip
|
81
90
|
end
|
82
91
|
|
83
92
|
def has_profile?(name)
|
data/lib/zoom/editor.rb
CHANGED
@@ -42,7 +42,7 @@ class Zoom::Editor
|
|
42
42
|
private :default
|
43
43
|
|
44
44
|
def initialize(editor)
|
45
|
-
@editor = editor
|
45
|
+
@editor, _, @flags = editor.partition(" ")
|
46
46
|
end
|
47
47
|
|
48
48
|
def open(results)
|
@@ -61,11 +61,13 @@ class Zoom::Editor
|
|
61
61
|
filename = result.filename
|
62
62
|
lineno = result.lineno
|
63
63
|
pwd = result.pwd
|
64
|
-
system(
|
64
|
+
system(
|
65
|
+
"#{@editor} #{@flags} +#{lineno} '#{pwd}/#{filename}'"
|
66
|
+
)
|
65
67
|
else
|
66
68
|
filename = result.contents
|
67
69
|
pwd = result.pwd
|
68
|
-
system("#{@editor} '#{pwd}/#{filename}'")
|
70
|
+
system("#{@editor} #{@flags} '#{pwd}/#{filename}'")
|
69
71
|
end
|
70
72
|
end
|
71
73
|
private :open_result
|
@@ -113,7 +115,9 @@ class Zoom::Editor
|
|
113
115
|
zq.close
|
114
116
|
zs.close
|
115
117
|
|
116
|
-
system(
|
118
|
+
system(
|
119
|
+
"#{@editor} #{@flags} -S #{source} '#{files.join("' '")}'"
|
120
|
+
)
|
117
121
|
|
118
122
|
FileUtils.rm_f(quickfix)
|
119
123
|
FileUtils.rm_f(source)
|
data/lib/zoom/error.rb
CHANGED
data/lib/zoom/profile.rb
CHANGED
@@ -3,9 +3,11 @@ require "scoobydoo"
|
|
3
3
|
require "shellwords"
|
4
4
|
|
5
5
|
class Zoom::Profile < Hash
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
attr_accessor :exts
|
7
|
+
attr_accessor :files
|
8
|
+
attr_accessor :format_flags
|
9
|
+
attr_accessor :regex
|
10
|
+
attr_accessor :taggable
|
9
11
|
|
10
12
|
def after(a = nil)
|
11
13
|
self["after"] = a.strip if (a)
|
@@ -35,30 +37,26 @@ class Zoom::Profile < Hash
|
|
35
37
|
|
36
38
|
def exe(header)
|
37
39
|
# Emulate grep
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
40
|
+
cmd = [
|
41
|
+
before,
|
42
|
+
tool,
|
43
|
+
@format_flags,
|
44
|
+
flags,
|
45
|
+
only_exts_and_files,
|
46
|
+
header["translated"],
|
47
|
+
header["args"],
|
48
|
+
"--",
|
49
|
+
header["regex"].shellescape,
|
50
|
+
header["paths"],
|
51
|
+
after
|
52
|
+
].join(" ").strip
|
53
|
+
|
54
|
+
if (header.has_key?("debug") && header["debug"])
|
55
|
+
puts cmd
|
56
|
+
return ""
|
49
57
|
else
|
50
|
-
cmd
|
51
|
-
before,
|
52
|
-
operator,
|
53
|
-
@format_flags,
|
54
|
-
flags,
|
55
|
-
header["args"],
|
56
|
-
header["pattern"].shellescape,
|
57
|
-
header["paths"],
|
58
|
-
after
|
59
|
-
].join(" ").strip
|
58
|
+
return %x(#{cmd})
|
60
59
|
end
|
61
|
-
return %x(#{cmd})
|
62
60
|
end
|
63
61
|
|
64
62
|
def flags(f = nil)
|
@@ -71,7 +69,7 @@ class Zoom::Profile < Hash
|
|
71
69
|
begin
|
72
70
|
return profile_by_name(json["class"]).new(
|
73
71
|
json["name"],
|
74
|
-
json["
|
72
|
+
json["tool"].nil? ? "" : json["tool"],
|
75
73
|
json["flags"].nil? ? "" : json["flags"],
|
76
74
|
json["before"].nil? ? "" : json["before"],
|
77
75
|
json["after"].nil? ? "" : json["after"]
|
@@ -83,8 +81,9 @@ class Zoom::Profile < Hash
|
|
83
81
|
end
|
84
82
|
end
|
85
83
|
|
86
|
-
def
|
87
|
-
|
84
|
+
def grep_like_format_flags(all = false)
|
85
|
+
@format_flags = "" # Set this to mirror basic grep
|
86
|
+
@taggable = false # Should results be tagged like grep
|
88
87
|
end
|
89
88
|
|
90
89
|
def hilight_after(str)
|
@@ -117,34 +116,41 @@ class Zoom::Profile < Hash
|
|
117
116
|
end
|
118
117
|
private :hilight_name
|
119
118
|
|
120
|
-
def
|
119
|
+
def hilight_regex(str)
|
121
120
|
return str if (!Zoom.hilight?)
|
122
|
-
return str
|
121
|
+
return str
|
123
122
|
end
|
124
|
-
private :
|
123
|
+
private :hilight_regex
|
125
124
|
|
126
|
-
def
|
125
|
+
def hilight_tool(str)
|
127
126
|
return str if (!Zoom.hilight?)
|
128
|
-
return str
|
127
|
+
return str.green
|
129
128
|
end
|
130
|
-
private :
|
129
|
+
private :hilight_tool
|
131
130
|
|
132
|
-
def initialize(n = nil,
|
131
|
+
def initialize(n = nil, t = nil, f = nil, b = nil, a = nil)
|
133
132
|
a ||= ""
|
134
133
|
b ||= ""
|
135
134
|
f ||= ""
|
136
135
|
n ||= camel_case_to_underscore(self.class.to_s)
|
137
|
-
|
136
|
+
t ||= "echo"
|
138
137
|
|
139
138
|
self["class"] = self.class.to_s
|
140
139
|
after(a)
|
141
140
|
before(b)
|
142
141
|
flags(f)
|
143
142
|
name(n)
|
144
|
-
|
143
|
+
tool(t)
|
144
|
+
|
145
|
+
@exts = Array.new # Set this to only search specified exts
|
146
|
+
@files = Array.new # Set this to noly search specified files
|
147
|
+
@regex = "" # Setting this will override user input
|
145
148
|
|
146
|
-
|
149
|
+
# In case someone overrides grep_like_format_flags
|
150
|
+
@format_flags = ""
|
147
151
|
@taggable = false
|
152
|
+
|
153
|
+
grep_like_format_flags
|
148
154
|
end
|
149
155
|
|
150
156
|
def name(n = nil)
|
@@ -153,56 +159,12 @@ class Zoom::Profile < Hash
|
|
153
159
|
return self["name"]
|
154
160
|
end
|
155
161
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
op = ScoobyDoo.where_are_you(o)
|
160
|
-
raise Zoom::Error::ExecutableNotFound.new(o) if (op.nil?)
|
161
|
-
self["operator"] = o
|
162
|
-
end
|
163
|
-
return self["operator"]
|
162
|
+
def only_exts_and_files
|
163
|
+
# Do nothing
|
164
|
+
return ""
|
164
165
|
end
|
165
166
|
|
166
167
|
def preprocess(header)
|
167
|
-
# Use hard-coded pattern if defined
|
168
|
-
if (
|
169
|
-
@pattern &&
|
170
|
-
!@pattern.empty? &&
|
171
|
-
(header["pattern"] != @pattern)
|
172
|
-
)
|
173
|
-
header["args"] += " #{header["pattern"]}"
|
174
|
-
header["pattern"] = @pattern
|
175
|
-
end
|
176
|
-
|
177
|
-
case operator.split("/")[-1]
|
178
|
-
when /^ack(-grep)?$/, "ag", "grep", "pt"
|
179
|
-
paths = header["paths"].split(" ")
|
180
|
-
if (header["pattern"].empty? && !paths.empty?)
|
181
|
-
header["pattern"] = paths.delete_at(0)
|
182
|
-
header["paths"] = paths.join(" ").strip
|
183
|
-
header["paths"] = "." if (header["paths"].empty?)
|
184
|
-
end
|
185
|
-
|
186
|
-
# This isn't done here anymore as it'll break hilighting
|
187
|
-
# header["pattern"] = header["pattern"].shellescape
|
188
|
-
when "find"
|
189
|
-
# If additional args are passed, then assume pattern is
|
190
|
-
# actually an arg
|
191
|
-
if (header["args"] && !header["args"].empty?)
|
192
|
-
header["args"] += " #{header["pattern"]}"
|
193
|
-
header["pattern"] = ""
|
194
|
-
end
|
195
|
-
|
196
|
-
# If pattern was provided then assume it's an iname search
|
197
|
-
if (header["pattern"] && !header["pattern"].empty?)
|
198
|
-
header["pattern"] = "-iname \"#{header["pattern"]}\""
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
# Translate any needed flags
|
203
|
-
header["args"] += " #{translate(header["translate"])}"
|
204
|
-
header["args"].strip!
|
205
|
-
|
206
168
|
return header
|
207
169
|
end
|
208
170
|
|
@@ -216,7 +178,7 @@ class Zoom::Profile < Hash
|
|
216
178
|
ObjectSpace.each_object(Class).select do |clas|
|
217
179
|
if (clas < self)
|
218
180
|
begin
|
219
|
-
clas.new
|
181
|
+
clas.new
|
220
182
|
true
|
221
183
|
rescue Zoom::Error::ExecutableNotFound
|
222
184
|
false
|
@@ -232,17 +194,27 @@ class Zoom::Profile < Hash
|
|
232
194
|
ret.push(hilight_name)
|
233
195
|
ret.push("#{hilight_class}\n")
|
234
196
|
ret.push(hilight_before(before)) if (!before.empty?)
|
235
|
-
ret.push(
|
197
|
+
ret.push(hilight_tool(tool)) if (!tool.empty?)
|
236
198
|
ret.push(hilight_flags(flags)) if (!flags.empty?)
|
237
|
-
if (@
|
238
|
-
ret.push(
|
199
|
+
if (@regex.nil? || @regex.empty?)
|
200
|
+
ret.push(hilight_regex("REGEX"))
|
239
201
|
else
|
240
|
-
ret.push(
|
202
|
+
ret.push(hilight_regex("\"#{@regex}\""))
|
241
203
|
end
|
242
204
|
ret.push(hilight_after(after)) if (!after.empty?)
|
243
205
|
return ret.join(" ").strip
|
244
206
|
end
|
245
207
|
|
208
|
+
def tool(t = nil)
|
209
|
+
if (t)
|
210
|
+
t.strip!
|
211
|
+
tl = ScoobyDoo.where_are_you(t)
|
212
|
+
raise Zoom::Error::ExecutableNotFound.new(t) if (tl.nil?)
|
213
|
+
self["tool"] = t
|
214
|
+
end
|
215
|
+
return self["tool"]
|
216
|
+
end
|
217
|
+
|
246
218
|
def translate(from)
|
247
219
|
return ""
|
248
220
|
end
|