ruby-zoom 3.5.0 → 4.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.
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