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
@@ -0,0 +1,121 @@
1
+ require "fileutils"
2
+ require "io/wait"
3
+
4
+ class Zoom::Editor
5
+ def default(results)
6
+ # First result should never be nil, but better safe than sorry
7
+ first_result = results.delete_at(0)
8
+ open_result(first_result) if (first_result)
9
+
10
+ results.each do |result|
11
+ print "Open result #{result.tag} [y]/n/q/l?: "
12
+ answer = nil
13
+ while (answer.nil?)
14
+ begin
15
+ system("stty raw -echo")
16
+ if ($stdin.ready?)
17
+ answer = $stdin.getc
18
+ else
19
+ sleep 0.1
20
+ end
21
+ ensure
22
+ system("stty -raw echo")
23
+ end
24
+ end
25
+ puts
26
+
27
+ case answer
28
+ when "n", "N"
29
+ # Do nothing
30
+ when "l", "L"
31
+ # Open this result then exit
32
+ open_result(result)
33
+ break
34
+ when "q", "Q", "\x03"
35
+ # Quit or ^C
36
+ break
37
+ else
38
+ open_result(result)
39
+ end
40
+ end
41
+ end
42
+ private :default
43
+
44
+ def initialize(editor)
45
+ @editor = editor
46
+ end
47
+
48
+ def open(results)
49
+ return if (results.nil? || results.empty?)
50
+
51
+ case @editor
52
+ when /vim?$/
53
+ vim(results)
54
+ else
55
+ default(results)
56
+ end
57
+ end
58
+
59
+ def open_result(result)
60
+ if (result.grep_like?)
61
+ filename = result.filename
62
+ lineno = result.lineno
63
+ pwd = result.pwd
64
+ system("#{@editor} +#{lineno} '#{pwd}/#{filename}'")
65
+ else
66
+ filename = result.contents
67
+ pwd = result.pwd
68
+ system("#{@editor} '#{pwd}/#{filename}'")
69
+ end
70
+ end
71
+ private :open_result
72
+
73
+ def vim(results)
74
+ quickfix = Pathname.new("~/.cache/zoom/quickfix").expand_path
75
+ source = Pathname.new("~/.cache/zoom/source").expand_path
76
+ FileUtils.mkdir_p(quickfix.dirname)
77
+
78
+ zq = File.open(quickfix, "w")
79
+ zs = File.open(source, "w")
80
+
81
+ vimscript = [
82
+ "augroup Zoom",
83
+ " autocmd!",
84
+ " autocmd FileType qf nnoremap <cr> :.cc<cr>:cclose<cr>",
85
+ "augroup END",
86
+ "",
87
+ "nnoremap <leader>z :copen<cr>",
88
+ "nnoremap zn :copen<cr>j:.cc<cr>:cclose<cr>",
89
+ "nnoremap zp :copen<cr>k:.cc<cr>:cclose<cr>",
90
+ ""
91
+ ].join("\n")
92
+ zs.write(vimscript)
93
+
94
+ files = Array.new
95
+ results.each do |result|
96
+ filename = result.filename if (result.grep_like?)
97
+ filename ||= result.contents
98
+ lineno = result.lineno
99
+ match = result.match
100
+ pwd = result.pwd
101
+
102
+ if (!files.include?("#{pwd}/#{filename}"))
103
+ files.push("#{pwd}/#{filename}")
104
+ zs.write("#{lineno}\nbnext\n") if (result.grep_like?)
105
+ end
106
+
107
+ if (result.grep_like?)
108
+ zq.write("#{pwd}/#{filename}|#{lineno}| #{match}\n")
109
+ end
110
+ end
111
+ zs.write("silent cfile #{quickfix}\n")
112
+
113
+ zq.close
114
+ zs.close
115
+
116
+ system("#{@editor} -S #{source} #{files.join(" ")}")
117
+
118
+ FileUtils.rm_f(quickfix)
119
+ FileUtils.rm_f(source)
120
+ end
121
+ end
@@ -1,9 +1,9 @@
1
1
  class Zoom::Error < RuntimeError
2
2
  end
3
3
 
4
- require "zoom/error/executable_not_found_error"
5
- require "zoom/error/invalid_tag_error"
6
- require "zoom/error/profile_already_exists_error"
7
- require "zoom/error/profile_can_not_be_modified_error"
8
- require "zoom/error/profile_class_unknown_error"
9
- require "zoom/error/profile_does_not_exist_error"
4
+ require "zoom/error/executable_not_found"
5
+ require "zoom/error/invalid_color"
6
+ require "zoom/error/invalid_tag"
7
+ require "zoom/error/profile_class_unknown"
8
+ require "zoom/error/profile_does_not_exist"
9
+ require "zoom/error/profile_not_named"
@@ -1,6 +1,4 @@
1
- require "zoom/error"
2
-
3
- class Zoom::Error::ExecutableNotFoundError < Zoom::Error
1
+ class Zoom::Error::ExecutableNotFound < Zoom::Error
4
2
  def initialize(exe = nil)
5
3
  super("Executable not found: #{exe}") if (exe)
6
4
  super("Executable not found") if (exe.nil?)
@@ -0,0 +1,5 @@
1
+ class Zoom::Error::InvalidColor < Zoom::Error
2
+ def initialize(color)
3
+ super("Invalid color: #{color}")
4
+ end
5
+ end
@@ -1,6 +1,4 @@
1
- require "zoom/error"
2
-
3
- class Zoom::Error::InvalidTagError < Zoom::Error
1
+ class Zoom::Error::InvalidTag < Zoom::Error
4
2
  def initialize(tag = nil)
5
3
  super("Invalid tag: #{tag}") if (tag)
6
4
  super("Invalid tag") if (tag.nil?)
@@ -1,6 +1,4 @@
1
- require "zoom/error"
2
-
3
- class Zoom::Error::ProfileClassUnknownError < Zoom::Error
1
+ class Zoom::Error::ProfileClassUnknown < Zoom::Error
4
2
  def initialize(clas = nil)
5
3
  super("Profile class unknown: #{clas}") if (clas)
6
4
  super("Profile class unknown") if (clas.nil?)
@@ -1,6 +1,4 @@
1
- require "zoom/error"
2
-
3
- class Zoom::Error::ProfileDoesNotExistError < Zoom::Error
1
+ class Zoom::Error::ProfileDoesNotExist < Zoom::Error
4
2
  def initialize(profile = nil)
5
3
  super("Profile does not exist: #{profile}") if (profile)
6
4
  super("Profile does not exist") if (profile.nil?)
@@ -0,0 +1,7 @@
1
+ require "json"
2
+
3
+ class Zoom::Error::ProfileNotNamed < Zoom::Error
4
+ def initialize(json)
5
+ super("Profile has no name:\n#{JSON.pretty_generate(json)}")
6
+ end
7
+ end
@@ -1,97 +1,171 @@
1
+ require "hilighter"
1
2
  require "scoobydoo"
2
3
  require "shellwords"
3
- require "zoom/error/profile_class_unknown_error"
4
4
 
5
5
  class Zoom::Profile < Hash
6
- attr_accessor :immutable
7
- attr_accessor :taggable
6
+ attr_reader :pattern
7
+ attr_reader :taggable
8
8
 
9
- @@cache_file = "~/.zoom_cache"
10
-
11
- def append(append = nil)
12
- self["append"] = append if (append)
13
- return self["append"]
9
+ def after(a = nil)
10
+ self["after"] = a if (a)
11
+ return self["after"].strip
14
12
  end
15
13
 
16
- def self.cache_file(cache_file)
17
- @@cache_file = cache_file
18
- @@cache_file ||= "~/.zoom_cache"
14
+ def before(b = nil)
15
+ self["before"] = b if (b)
16
+ return self["before"].strip
19
17
  end
20
18
 
21
- def colors
22
- # TODO color support
23
- ""
19
+ def class_name
20
+ return self["class"]
24
21
  end
25
22
 
26
23
  def exe(args, pattern)
27
- system("#{self.to_s} #{args} #{pattern} #{self.append}")
24
+ # Use hard-coded pattern if defined
25
+ pattern = @pattern if (@pattern && !@pattern.empty?)
26
+
27
+ # If not pattern and no after, then return nothing
28
+ if (pattern.nil? || pattern.empty?)
29
+ return "" if (after.nil? || after.empty? || after == ".")
30
+ end
31
+
32
+ # Emulate grep
33
+ case operator.split("/")[-1]
34
+ when "ack", "ack-grep"
35
+ str = [
36
+ before,
37
+ operator,
38
+ "-H --nobreak --nocolor --noheading -s",
39
+ flags
40
+ ].join(" ").strip
41
+ return %x(#{str} #{args} #{pattern.shellescape} #{after})
42
+ when "ag"
43
+ str = [
44
+ before,
45
+ operator,
46
+ "--filename --nobreak --nocolor --noheading --silent",
47
+ flags
48
+ ].join(" ").strip
49
+ return %x(#{str} #{args} #{pattern.shellescape} #{after})
50
+ when "find"
51
+ str = [before, operator, flags].join(" ").strip
52
+ return %x(#{str} #{args} \"#{pattern}\" #{after})
53
+ when "grep"
54
+ str = [
55
+ before,
56
+ operator,
57
+ "--color=never -EHnRs",
58
+ "--exclude-dir=.bzr",
59
+ "--exclude-dir=.git",
60
+ "--exclude-dir=.svn",
61
+ flags
62
+ ].join(" ").strip
63
+ return %x(#{str} #{args} #{pattern.shellescape} #{after})
64
+ when "pt"
65
+ str = [
66
+ before,
67
+ operator,
68
+ "-e --nocolor --nogroup",
69
+ flags
70
+ ].join(" ").strip
71
+ return %x(#{str} #{args} #{pattern.shellescape} #{after})
72
+ else
73
+ str = [before, operator, flags].join(" ").strip
74
+ return %x(#{str} #{args} #{pattern} #{after})
75
+ end
28
76
  end
29
77
 
30
- def flags(flags = nil)
31
- self["flags"] = flags if (flags)
32
- return self["flags"]
78
+ def flags(f = nil)
79
+ self["flags"] = f if (f)
80
+ return self["flags"].strip
33
81
  end
34
82
 
35
83
  def self.from_json(json)
36
84
  begin
37
85
  return profile_by_name(json["class"]).new(
86
+ json["name"],
38
87
  json["operator"].nil? ? "" : json["operator"],
39
88
  json["flags"].nil? ? "" : json["flags"],
40
- json["prepend"].nil? ? "" : json["prepend"],
41
- json["append"].nil? ? "" : json["append"]
42
- )
43
- rescue NameError => e
44
- raise Zoom::Error::ProfileClassUnknownError.new(
45
- json["class"]
89
+ json["before"].nil? ? "" : json["before"],
90
+ json["after"].nil? ? "" : json["after"]
46
91
  )
92
+ rescue NoMethodError
93
+ raise Zoom::Error::ProfileNotNamed.new(json)
94
+ rescue NameError
95
+ raise Zoom::Error::ProfileClassUnknown.new(json["class"])
47
96
  end
48
97
  end
49
98
 
50
- def info
51
- [
52
- "Class : #{self.class.to_s}",
53
- "Prepend : #{self["prepend"]}",
54
- "Operator: #{self["operator"]}",
55
- "Flags : #{self["flags"]}",
56
- "Append : #{self["append"]}"
57
- ].join("\n").strip
99
+ def go(editor, results)
100
+ Zoom::Editor.new(editor).open(results)
101
+ end
102
+
103
+ def hilight_after(str)
104
+ return str if (!Zoom.hilight?)
105
+ return str.yellow
106
+ end
107
+ private :hilight_after
108
+
109
+ def hilight_before(str)
110
+ return str if (!Zoom.hilight?)
111
+ return str.yellow
112
+ end
113
+ private :hilight_before
114
+
115
+ def hilight_class
116
+ return class_name if (!Zoom.hilight?)
117
+ return class_name.cyan
118
+ end
119
+ private :hilight_class
120
+
121
+ def hilight_flags(str)
122
+ return str if (!Zoom.hilight?)
123
+ return str.magenta
124
+ end
125
+ private :hilight_flags
126
+
127
+ def hilight_name
128
+ return name if (!Zoom.hilight?)
129
+ return name.white
130
+ end
131
+ private :hilight_name
132
+
133
+ def hilight_operator(str)
134
+ return str if (!Zoom.hilight?)
135
+ return str.green
136
+ end
137
+ private :hilight_operator
138
+
139
+ def hilight_pattern(str)
140
+ return str if (!Zoom.hilight?)
141
+ return str
58
142
  end
143
+ private :hilight_pattern
59
144
 
60
- def initialize(
61
- operator = "echo",
62
- flags = "#",
63
- envprepend = "",
64
- append = ""
65
- )
145
+ def initialize(n, o = "echo", f = "#", b = "", a = "")
66
146
  self["class"] = self.class.to_s
67
- self.flags(flags)
68
- self.prepend(envprepend)
69
- self.append(append)
70
- self.operator(operator)
147
+ after(a)
148
+ before(b)
149
+ flags(f.split(" ").uniq.join(" "))
150
+ name(n)
151
+ operator(o)
71
152
 
72
- @immutable = false
73
- @pager = "z --pager --cache-file #{@@cache_file}"
153
+ @pattern = "" # Setting this will override user input
74
154
  @taggable = false
75
155
  end
76
156
 
77
- def operator(operator = nil)
78
- if (operator)
79
- op = ScoobyDoo.where_are_you(operator)
80
- if (op)
81
- self["operator"] = op
82
- else
83
- self["operator"] = ScoobyDoo.where_are_you("echo")
84
- flags("")
85
- prepend("")
86
- append("#{operator} is not installed!")
87
- end
88
- end
89
- return self["operator"]
157
+ def name(n = nil)
158
+ self["name"] = n if (n)
159
+ return self["name"].strip
90
160
  end
91
161
 
92
- def prepend(envprepend = nil)
93
- self["prepend"] = envprepend if (envprepend)
94
- return self["prepend"]
162
+ def operator(o = nil)
163
+ if (o)
164
+ op = ScoobyDoo.where_are_you(o)
165
+ raise Zoom::Error::ExecutableNotFound.new(o) if (op.nil?)
166
+ self["operator"] = o
167
+ end
168
+ return self["operator"].strip
95
169
  end
96
170
 
97
171
  def self.profile_by_name(clas)
@@ -100,13 +174,35 @@ class Zoom::Profile < Hash
100
174
  end
101
175
  end
102
176
 
177
+ def self.subclasses
178
+ ObjectSpace.each_object(Class).select do |clas|
179
+ if (clas < self)
180
+ begin
181
+ clas.new(clas.to_s)
182
+ true
183
+ rescue Zoom::Error::ExecutableNotFound
184
+ false
185
+ end
186
+ else
187
+ false
188
+ end
189
+ end
190
+ end
191
+
103
192
  def to_s
104
- [
105
- self.colors,
106
- self["prepend"],
107
- self["operator"],
108
- self["flags"]
109
- ].join(" ").strip
193
+ ret = Array.new
194
+ ret.push(hilight_name)
195
+ ret.push("#{hilight_class}\n")
196
+ ret.push(hilight_before(before)) if (!before.empty?)
197
+ ret.push(hilight_operator(operator)) if (!operator.empty?)
198
+ ret.push(hilight_flags(flags)) if (!flags.empty?)
199
+ if (@pattern.nil? || @pattern.empty?)
200
+ ret.push(hilight_pattern("PATTERN"))
201
+ else
202
+ ret.push(hilight_pattern("\"#{@pattern}\""))
203
+ end
204
+ ret.push(hilight_after(after)) if (!after.empty?)
205
+ return ret.join(" ").strip
110
206
  end
111
207
  end
112
208