searchlink 2.3.69 → 2.3.70
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.
- checksums.yaml +4 -4
- data/lib/searchlink/exceptions.rb +29 -0
- data/lib/searchlink/output.rb +7 -4
- data/lib/searchlink/parse.rb +214 -190
- data/lib/searchlink/script_plugin.rb +84 -0
- data/lib/searchlink/searches/helpers/chromium.rb +32 -31
- data/lib/searchlink/searches.rb +32 -7
- data/lib/searchlink/semver.rb +7 -7
- data/lib/searchlink/string.rb +8 -0
- data/lib/searchlink/version.rb +1 -1
- data/lib/searchlink.rb +7 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 94434b4c63f4188ca00e93ad4c2be7765b61a2fdbccd3b7e706482bf1e09b618
|
|
4
|
+
data.tar.gz: 4af48f283d1a693bed323cdbbb91121ee5b4616225d4ecef46f80302016227ff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3fa2094dbbf341680baefae73f98aba890ace10c6f6d44198b7902c28810b9e3cc8121199b9ba26a1da0243dcf779c3f018ebaaa6f1e794456d72106fafe5ad6
|
|
7
|
+
data.tar.gz: 7a39a40fbc8e8466c3652e236eee03091b027dd83aebd481b31dcb3acaa3a53124d362887d4cbe33bc22699fadd4e7adfe40f4f40db48cb8f69754584d84ae70
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SL
|
|
4
|
+
# Custom Semantic Versioning error
|
|
5
|
+
class VersionError < StandardError
|
|
6
|
+
def initialize(msg)
|
|
7
|
+
msg = msg ? ": #{msg}" : ''
|
|
8
|
+
puts "Versioning error#{msg}"
|
|
9
|
+
|
|
10
|
+
super()
|
|
11
|
+
|
|
12
|
+
Process.exit 1
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Custom plugin error
|
|
17
|
+
class PluginError < StandardError
|
|
18
|
+
def initialize(msg = nil, plugin: nil)
|
|
19
|
+
plugin = %("#{plugin}") if plugin
|
|
20
|
+
plugin ||= 'plugin'
|
|
21
|
+
msg = ": #{msg}" if msg
|
|
22
|
+
puts "Error in #{plugin}#{msg}"
|
|
23
|
+
|
|
24
|
+
super()
|
|
25
|
+
|
|
26
|
+
Process.exit 1
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/searchlink/output.rb
CHANGED
|
@@ -62,13 +62,16 @@ module SL
|
|
|
62
62
|
|
|
63
63
|
# Posts macOS notifications
|
|
64
64
|
#
|
|
65
|
-
# @param
|
|
66
|
-
# @param
|
|
65
|
+
# @param title [String] The title of the notification
|
|
66
|
+
# @param subtitle [String] The text of the notification
|
|
67
67
|
#
|
|
68
|
-
def notify(
|
|
68
|
+
def notify(title, subtitle)
|
|
69
69
|
return unless SL.config['notifications']
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
title = title.gsub(/"/, '\\"')
|
|
72
|
+
subtitle = subtitle.gsub(/"/, '\\"')
|
|
73
|
+
|
|
74
|
+
`osascript -e 'display notification "SearchLink" with title "#{title}" subtitle "#{subtitle}"'`
|
|
72
75
|
end
|
|
73
76
|
end
|
|
74
77
|
end
|
data/lib/searchlink/parse.rb
CHANGED
|
@@ -20,14 +20,14 @@ module SL
|
|
|
20
20
|
|
|
21
21
|
input.parse_flags! unless skip_flags
|
|
22
22
|
|
|
23
|
-
options = %w[debug country_code inline prefix_random include_titles remove_seo validate_links]
|
|
23
|
+
options = %w[debug country_code inline prefix_random include_titles remove_seo validate_links complete_bare]
|
|
24
24
|
options.each do |o|
|
|
25
25
|
if input =~ /^ *#{o}:\s+(\S+)$/
|
|
26
26
|
val = Regexp.last_match(1).strip
|
|
27
27
|
val = true if val =~ /true/i
|
|
28
28
|
val = false if val =~ /false/i
|
|
29
29
|
SL.config[o] = val
|
|
30
|
-
|
|
30
|
+
warn "\r\033[0KGlobal config: #{o} = #{SL.config[o]}\n" unless SILENT
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
next if skip_flags
|
|
@@ -57,7 +57,7 @@ module SL
|
|
|
57
57
|
case input.strip
|
|
58
58
|
when /^!?help$/i
|
|
59
59
|
if SILENT
|
|
60
|
-
help_dialog
|
|
60
|
+
help_dialog
|
|
61
61
|
else
|
|
62
62
|
$stdout.puts SL.version_check.to_s
|
|
63
63
|
$stdout.puts 'See https://github.com/ttscoff/searchlink/wiki for help'
|
|
@@ -75,6 +75,117 @@ module SL
|
|
|
75
75
|
Process.exit 0
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
def create_footnote(mtch)
|
|
79
|
+
if mtch[1].nil? || mtch[1] == ''
|
|
80
|
+
match
|
|
81
|
+
else
|
|
82
|
+
note = mtch[1].strip
|
|
83
|
+
@footnote_counter += 1
|
|
84
|
+
ref = if !@link_text.empty? && @link_text.scan(/\s/).empty?
|
|
85
|
+
@link_text
|
|
86
|
+
else
|
|
87
|
+
format('%<p>sfn%<c>04d', p: @prefix, c: @footnote_counter)
|
|
88
|
+
end
|
|
89
|
+
SL.add_footer "[^#{ref}]: #{note}"
|
|
90
|
+
res = "[^#{ref}]"
|
|
91
|
+
@cursor_difference += (SL.match_length - res.length)
|
|
92
|
+
SL.match_length = res.length
|
|
93
|
+
SL.add_report("#{@match_string} => Footnote #{ref}")
|
|
94
|
+
res
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def add_title(link_info)
|
|
99
|
+
@url = link_info
|
|
100
|
+
title = SL::URL.title(@url)
|
|
101
|
+
@link_text = title
|
|
102
|
+
|
|
103
|
+
if @ref_title
|
|
104
|
+
unless @links.key? @url
|
|
105
|
+
@links[@url] = @link_text
|
|
106
|
+
SL.add_footer SL.make_link(:ref_title, @link_text, @url, title: title, force_title: false)
|
|
107
|
+
end
|
|
108
|
+
@delete_line = true
|
|
109
|
+
elsif SL.config['inline']
|
|
110
|
+
res = SL.make_link(:inline, @link_text, @url, title: title, force_title: false)
|
|
111
|
+
@cursor_difference += SL.match_length - res.length
|
|
112
|
+
SL.match_length = res.length
|
|
113
|
+
SL.add_report("#{@match_string} => #{@url}")
|
|
114
|
+
res
|
|
115
|
+
else
|
|
116
|
+
unless @links.key? @url
|
|
117
|
+
@highest_marker += 1
|
|
118
|
+
@links[@url] = format('%<pre>s%<m>04d', pre: @prefix, m: @highest_marker)
|
|
119
|
+
SL.add_footer SL.make_link(:ref_title, @links[@url], @url, title: title, force_title: false)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
type = SL.config['inline'] ? :inline : :ref_link
|
|
123
|
+
res = SL.make_link(type, @link_text, @links[@url], title: false, force_title: false)
|
|
124
|
+
@cursor_difference += SL.match_length - res.length
|
|
125
|
+
SL.match_length = res.length
|
|
126
|
+
SL.add_report("#{@match_string} => #{@url}")
|
|
127
|
+
res
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def custom_search(search_type, search_terms)
|
|
132
|
+
SL.config['custom_site_searches'].each do |k, v|
|
|
133
|
+
next unless search_type == k
|
|
134
|
+
|
|
135
|
+
@link_text = search_terms if !SL.titleize && @link_text == ''
|
|
136
|
+
v = parse_arguments(v, { no_restore: true })
|
|
137
|
+
if v =~ %r{^(/|http)}i
|
|
138
|
+
search_type = 'r'
|
|
139
|
+
tokens = v.scan(/\$term\d+[ds]?/).sort.uniq
|
|
140
|
+
|
|
141
|
+
if !tokens.empty?
|
|
142
|
+
highest_token = 0
|
|
143
|
+
tokens.each do |token|
|
|
144
|
+
if token =~ /(\d+)[ds]?$/ && Regexp.last_match(1).to_i > highest_token
|
|
145
|
+
highest_token = Regexp.last_match(1).to_i
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
terms_p = search_terms.split(/ +/)
|
|
149
|
+
if terms_p.length > highest_token
|
|
150
|
+
remainder = terms_p[highest_token - 1..-1].join(' ')
|
|
151
|
+
terms_p = terms_p[0..highest_token - 2]
|
|
152
|
+
terms_p.push(remainder)
|
|
153
|
+
end
|
|
154
|
+
tokens.each do |t|
|
|
155
|
+
next unless t =~ /(\d+)[ds]?$/
|
|
156
|
+
|
|
157
|
+
int = Regexp.last_match(1).to_i - 1
|
|
158
|
+
replacement = terms_p[int]
|
|
159
|
+
case t
|
|
160
|
+
when /d$/
|
|
161
|
+
replacement.downcase!
|
|
162
|
+
re_down = ''
|
|
163
|
+
when /s$/
|
|
164
|
+
replacement.slugify!
|
|
165
|
+
re_down = ''
|
|
166
|
+
else
|
|
167
|
+
re_down = '(?!d|s)'
|
|
168
|
+
end
|
|
169
|
+
v.gsub!(/#{Regexp.escape(t) + re_down}/, replacement.url_encode)
|
|
170
|
+
end
|
|
171
|
+
search_terms = v
|
|
172
|
+
else
|
|
173
|
+
search_terms = v.gsub(/\$term[ds]?/i) do |mtch|
|
|
174
|
+
search_terms.downcase! if mtch =~ /d$/i
|
|
175
|
+
search_terms.slugify! if mtch =~ /s$/i
|
|
176
|
+
search_terms.url_encode
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
else
|
|
180
|
+
search_type = SL::GoogleSearch.api_key? ? 'gg' : 'g'
|
|
181
|
+
search_terms = "site:#{v} #{search_terms}"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
break
|
|
185
|
+
end
|
|
186
|
+
[search_type, search_terms]
|
|
187
|
+
end
|
|
188
|
+
|
|
78
189
|
def parse(input)
|
|
79
190
|
SL.output = []
|
|
80
191
|
return false if input.empty?
|
|
@@ -94,7 +205,7 @@ module SL
|
|
|
94
205
|
SL.add_output("<!-- v#{latest_version} available, run SearchLink on the word 'update' to install. -->")
|
|
95
206
|
end
|
|
96
207
|
|
|
97
|
-
links = {}
|
|
208
|
+
@links = {}
|
|
98
209
|
SL.footer = []
|
|
99
210
|
counter_links = 0
|
|
100
211
|
counter_errors = 0
|
|
@@ -102,9 +213,9 @@ module SL
|
|
|
102
213
|
input.sub!(/\n?<!-- Report:.*?-->\n?/m, '')
|
|
103
214
|
input.sub!(/\n?<!-- Errors:.*?-->\n?/m, '')
|
|
104
215
|
|
|
105
|
-
input.scan(/\[(.*?)\]:\s+(.*?)\n/).each { |match| links[match[1].strip] = match[0] }
|
|
216
|
+
input.scan(/\[(.*?)\]:\s+(.*?)\n/).each { |match| @links[match[1].strip] = match[0] }
|
|
106
217
|
|
|
107
|
-
prefix = if SL.config['prefix_random']
|
|
218
|
+
@prefix = if SL.config['prefix_random']
|
|
108
219
|
if input =~ /\[(\d{4}-)\d+\]: \S+/
|
|
109
220
|
Regexp.last_match(1)
|
|
110
221
|
else
|
|
@@ -114,16 +225,27 @@ module SL
|
|
|
114
225
|
''
|
|
115
226
|
end
|
|
116
227
|
|
|
117
|
-
highest_marker = 0
|
|
118
|
-
input.scan(/^\s{,3}\[(?:#{prefix})?(\d+)\]: /).each do
|
|
228
|
+
@highest_marker = 0
|
|
229
|
+
input.scan(/^\s{,3}\[(?:#{@prefix})?(\d+)\]: /).each do
|
|
119
230
|
m = Regexp.last_match
|
|
120
|
-
highest_marker = m[1].to_i if m[1].to_i > highest_marker
|
|
231
|
+
@highest_marker = m[1].to_i if m[1].to_i > @highest_marker
|
|
121
232
|
end
|
|
122
233
|
|
|
123
|
-
footnote_counter = 0
|
|
124
|
-
input.scan(/^\s{,3}\[\^(?:#{prefix})?fn(\d+)\]: /).each do
|
|
234
|
+
@footnote_counter = 0
|
|
235
|
+
input.scan(/^\s{,3}\[\^(?:#{@prefix})?fn(\d+)\]: /).each do
|
|
125
236
|
m = Regexp.last_match
|
|
126
|
-
footnote_counter = m[1].to_i if m[1].to_i > footnote_counter
|
|
237
|
+
@footnote_counter = m[1].to_i if m[1].to_i > @footnote_counter
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
if SL.config['complete_bare']
|
|
241
|
+
rx = %r{(?ix-m)(?<!\(|:\s|<)(?:
|
|
242
|
+
(?:https?://)(?:[\da-z.-]+)\.(?:[a-z.]{2,6})
|
|
243
|
+
(?:[/\w\d.\-()_/+=?&%]*?(?=[\s\n]|$))
|
|
244
|
+
)}
|
|
245
|
+
input.gsub!(rx) do
|
|
246
|
+
url_match = Regexp.last_match
|
|
247
|
+
url_match.pre_match =~ /!\S+ +$/ ? url_match[0] : "[%](#{url_match[0]})"
|
|
248
|
+
end
|
|
127
249
|
end
|
|
128
250
|
|
|
129
251
|
if input =~ /\[(.*?)\]\((.*?)\)/
|
|
@@ -135,7 +257,7 @@ module SL
|
|
|
135
257
|
line_difference = 0
|
|
136
258
|
lines.each_with_index do |line, num|
|
|
137
259
|
SL.line_num = num - line_difference
|
|
138
|
-
cursor_difference = 0
|
|
260
|
+
@cursor_difference = 0
|
|
139
261
|
# ignore links in code blocks
|
|
140
262
|
if line =~ /^( {4,}|\t+)[^*+\-]/
|
|
141
263
|
out.push(line)
|
|
@@ -155,22 +277,22 @@ module SL
|
|
|
155
277
|
next
|
|
156
278
|
end
|
|
157
279
|
|
|
158
|
-
delete_line = false
|
|
280
|
+
@delete_line = false
|
|
159
281
|
|
|
160
|
-
search_count = 0
|
|
282
|
+
@search_count = 0
|
|
161
283
|
|
|
162
284
|
line.gsub!(/\[(.*?)\]\((.*?)\)/) do |match|
|
|
163
285
|
this_match = Regexp.last_match
|
|
164
|
-
SL.match_column = this_match.begin(0) - cursor_difference
|
|
165
|
-
match_string = this_match.to_s
|
|
166
|
-
SL.match_length = match_string.length
|
|
286
|
+
SL.match_column = this_match.begin(0) - @cursor_difference
|
|
287
|
+
@match_string = this_match.to_s
|
|
288
|
+
SL.match_length = @match_string.length
|
|
167
289
|
match_before = this_match.pre_match
|
|
168
290
|
|
|
169
291
|
invalid_search = false
|
|
170
|
-
ref_title = false
|
|
292
|
+
@ref_title = false
|
|
171
293
|
|
|
172
294
|
if match_before.scan(/(^|[^\\])`/).length.odd?
|
|
173
|
-
SL.add_report("Match '#{match_string}' within an inline code block")
|
|
295
|
+
SL.add_report("Match '#{@match_string}' within an inline code block")
|
|
174
296
|
invalid_search = true
|
|
175
297
|
end
|
|
176
298
|
|
|
@@ -179,14 +301,14 @@ module SL
|
|
|
179
301
|
$stderr.print("\033[0K\rProcessed: #{counter_links} of #{total_links}, #{counter_errors} errors. ")
|
|
180
302
|
end
|
|
181
303
|
|
|
182
|
-
link_text = this_match[1] || ''
|
|
304
|
+
@link_text = this_match[1] || ''
|
|
183
305
|
link_info = parse_arguments(this_match[2].strip).strip || ''
|
|
184
306
|
|
|
185
|
-
if link_text.strip == '' && link_info =~ /".*?"/
|
|
307
|
+
if @link_text.strip == '' && link_info =~ /".*?"/
|
|
186
308
|
link_info.gsub!(/"(.*?)"/) do
|
|
187
|
-
m = Regexp.last_match
|
|
188
|
-
link_text = m if link_text == ''
|
|
189
|
-
|
|
309
|
+
m = Regexp.last_match
|
|
310
|
+
@link_text = m[1] if @link_text == ''
|
|
311
|
+
m[0]
|
|
190
312
|
end
|
|
191
313
|
end
|
|
192
314
|
|
|
@@ -195,11 +317,11 @@ module SL
|
|
|
195
317
|
end
|
|
196
318
|
|
|
197
319
|
if link_info.strip =~ /:$/ && line.strip == match
|
|
198
|
-
ref_title = true
|
|
320
|
+
@ref_title = true
|
|
199
321
|
link_info.sub!(/\s*:\s*$/, '')
|
|
200
322
|
end
|
|
201
323
|
|
|
202
|
-
unless
|
|
324
|
+
unless !@link_text.empty? || !link_info.sub(/^[!\^]\S+/, '').strip.empty?
|
|
203
325
|
SL.add_error('No input', match)
|
|
204
326
|
counter_errors += 1
|
|
205
327
|
invalid_search = true
|
|
@@ -217,60 +339,15 @@ module SL
|
|
|
217
339
|
match
|
|
218
340
|
elsif link_info =~ /^\^(.+)/
|
|
219
341
|
m = Regexp.last_match
|
|
220
|
-
|
|
221
|
-
match
|
|
222
|
-
else
|
|
223
|
-
note = m[1].strip
|
|
224
|
-
footnote_counter += 1
|
|
225
|
-
ref = if !link_text.empty? && link_text.scan(/\s/).empty?
|
|
226
|
-
link_text
|
|
227
|
-
else
|
|
228
|
-
format('%<p>sfn%<c>04d', p: prefix, c: footnote_counter)
|
|
229
|
-
end
|
|
230
|
-
SL.add_footer "[^#{ref}]: #{note}"
|
|
231
|
-
res = "[^#{ref}]"
|
|
232
|
-
cursor_difference += (SL.match_length - res.length)
|
|
233
|
-
SL.match_length = res.length
|
|
234
|
-
SL.add_report("#{match_string} => Footnote #{ref}")
|
|
235
|
-
res
|
|
236
|
-
end
|
|
342
|
+
create_footnote(m)
|
|
237
343
|
# Handle [](URL) and [%](URL), filling in title
|
|
238
|
-
elsif (link_text == '' || link_text == '%') && SL::URL.url?(link_info)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
link_text = title
|
|
242
|
-
|
|
243
|
-
if ref_title
|
|
244
|
-
unless links.key? url
|
|
245
|
-
links[url] = link_text
|
|
246
|
-
SL.add_footer SL.make_link(:ref_title, link_text, url, title: title, force_title: false)
|
|
247
|
-
end
|
|
248
|
-
delete_line = true
|
|
249
|
-
elsif SL.config['inline']
|
|
250
|
-
res = SL.make_link(:inline, link_text, url, title: title, force_title: false)
|
|
251
|
-
cursor_difference += SL.match_length - res.length
|
|
252
|
-
SL.match_length = res.length
|
|
253
|
-
SL.add_report("#{match_string} => #{url}")
|
|
254
|
-
res
|
|
255
|
-
else
|
|
256
|
-
unless links.key? url
|
|
257
|
-
highest_marker += 1
|
|
258
|
-
links[url] = format('%<pre>s%<m>04d', pre: prefix, m: highest_marker)
|
|
259
|
-
SL.add_footer SL.make_link(:ref_title, links[url], url, title: title, force_title: false)
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
type = SL.config['inline'] ? :inline : :ref_link
|
|
263
|
-
res = SL.make_link(type, link_text, links[url], title: false, force_title: false)
|
|
264
|
-
cursor_difference += SL.match_length - res.length
|
|
265
|
-
SL.match_length = res.length
|
|
266
|
-
SL.add_report("#{match_string} => #{url}")
|
|
267
|
-
res
|
|
268
|
-
end
|
|
269
|
-
elsif (link_text == '' && link_info == '') || SL::URL.url?(link_info)
|
|
344
|
+
elsif (@link_text == '' || @link_text == '%') && SL::URL.url?(link_info)
|
|
345
|
+
add_title(link_info)
|
|
346
|
+
elsif (@link_text == '' && link_info == '') || SL::URL.url?(link_info)
|
|
270
347
|
SL.add_error('Invalid search', match) unless SL::URL.url?(link_info)
|
|
271
348
|
match
|
|
272
349
|
else
|
|
273
|
-
link_info = link_text if
|
|
350
|
+
link_info = @link_text if !@link_text.empty? && link_info == ''
|
|
274
351
|
|
|
275
352
|
search_type = ''
|
|
276
353
|
search_terms = ''
|
|
@@ -291,15 +368,15 @@ module SL
|
|
|
291
368
|
search_terms.strip!
|
|
292
369
|
|
|
293
370
|
# if the link text is just '%' replace with title regardless of config settings
|
|
294
|
-
if link_text == '%' && search_terms && !search_terms.empty?
|
|
371
|
+
if @link_text == '%' && search_terms && !search_terms.empty?
|
|
295
372
|
SL.titleize = true
|
|
296
|
-
link_text = ''
|
|
373
|
+
@link_text = ''
|
|
297
374
|
end
|
|
298
375
|
|
|
299
|
-
search_terms = link_text if search_terms == ''
|
|
376
|
+
search_terms = @link_text if search_terms == ''
|
|
300
377
|
|
|
301
378
|
# if the input starts with a +, append it to the link text as the search terms
|
|
302
|
-
search_terms = "#{link_text} #{search_terms.strip.sub(/^\+\s*/, '')}" if search_terms.strip =~ /^\+[^+]/
|
|
379
|
+
search_terms = "#{@link_text} #{search_terms.strip.sub(/^\+\s*/, '')}" if search_terms.strip =~ /^\+[^+]/
|
|
303
380
|
|
|
304
381
|
# if the end of input contain "^", copy to clipboard instead of STDOUT
|
|
305
382
|
SL.clipboard = true if search_terms =~ /(!!)?\^(!!)?$/
|
|
@@ -314,19 +391,19 @@ module SL
|
|
|
314
391
|
|
|
315
392
|
if search_word && SL::Searches.valid_search?(search_word[1])
|
|
316
393
|
search_type = search_word[1] unless search_word.nil?
|
|
317
|
-
search_terms = link_text
|
|
394
|
+
search_terms = @link_text
|
|
318
395
|
elsif search_word && search_word[1] =~ /^(\S+\.)+\S+$/
|
|
319
396
|
search_type = SL::GoogleSearch.api_key? ? 'gg' : 'g'
|
|
320
397
|
puts SL::GoogleSearch.api_key?
|
|
321
|
-
search_terms = "site:#{search_word[1]} #{link_text}"
|
|
398
|
+
search_terms = "site:#{search_word[1]} #{@link_text}"
|
|
322
399
|
else
|
|
323
400
|
SL.add_error("Invalid search#{SL::Searches.did_you_mean(search_word[1])}", match)
|
|
324
401
|
search_type = false
|
|
325
402
|
search_terms = false
|
|
326
403
|
end
|
|
327
|
-
elsif link_text &&
|
|
404
|
+
elsif @link_text && !@link_text.empty? && (!link_info || link_info.empty?)
|
|
328
405
|
search_type = SL::GoogleSearch.api_key? ? 'gg' : 'g'
|
|
329
|
-
search_terms = link_text
|
|
406
|
+
search_terms = @link_text
|
|
330
407
|
elsif link_info && !link_info.empty?
|
|
331
408
|
search_type = SL::GoogleSearch.api_key? ? 'gg' : 'g'
|
|
332
409
|
search_terms = link_info
|
|
@@ -337,109 +414,56 @@ module SL
|
|
|
337
414
|
end
|
|
338
415
|
|
|
339
416
|
if search_type && !search_terms.empty?
|
|
340
|
-
|
|
341
|
-
next unless search_type == k
|
|
342
|
-
|
|
343
|
-
link_text = search_terms if !SL.titleize && link_text == ''
|
|
344
|
-
v = parse_arguments(v, { no_restore: true })
|
|
345
|
-
if v =~ %r{^(/|http)}i
|
|
346
|
-
search_type = 'r'
|
|
347
|
-
tokens = v.scan(/\$term\d+[ds]?/).sort.uniq
|
|
348
|
-
|
|
349
|
-
if !tokens.empty?
|
|
350
|
-
highest_token = 0
|
|
351
|
-
tokens.each do |token|
|
|
352
|
-
if token =~ /(\d+)[ds]?$/ && Regexp.last_match(1).to_i > highest_token
|
|
353
|
-
highest_token = Regexp.last_match(1).to_i
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
terms_p = search_terms.split(/ +/)
|
|
357
|
-
if terms_p.length > highest_token
|
|
358
|
-
remainder = terms_p[highest_token - 1..-1].join(' ')
|
|
359
|
-
terms_p = terms_p[0..highest_token - 2]
|
|
360
|
-
terms_p.push(remainder)
|
|
361
|
-
end
|
|
362
|
-
tokens.each do |t|
|
|
363
|
-
next unless t =~ /(\d+)[ds]?$/
|
|
364
|
-
|
|
365
|
-
int = Regexp.last_match(1).to_i - 1
|
|
366
|
-
replacement = terms_p[int]
|
|
367
|
-
case t
|
|
368
|
-
when /d$/
|
|
369
|
-
replacement.downcase!
|
|
370
|
-
re_down = ''
|
|
371
|
-
when /s$/
|
|
372
|
-
replacement.slugify!
|
|
373
|
-
re_down = ''
|
|
374
|
-
else
|
|
375
|
-
re_down = '(?!d|s)'
|
|
376
|
-
end
|
|
377
|
-
v.gsub!(/#{Regexp.escape(t) + re_down}/, replacement.url_encode)
|
|
378
|
-
end
|
|
379
|
-
search_terms = v
|
|
380
|
-
else
|
|
381
|
-
search_terms = v.gsub(/\$term[ds]?/i) do |mtch|
|
|
382
|
-
search_terms.downcase! if mtch =~ /d$/i
|
|
383
|
-
search_terms.slugify! if mtch =~ /s$/i
|
|
384
|
-
search_terms.url_encode
|
|
385
|
-
end
|
|
386
|
-
end
|
|
387
|
-
else
|
|
388
|
-
search_type = SL::GoogleSearch.api_key? ? 'gg' : 'g'
|
|
389
|
-
search_terms = "site:#{v} #{search_terms}"
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
break
|
|
393
|
-
end
|
|
417
|
+
search_type, search_terms = custom_search(search_type, search_terms)
|
|
394
418
|
end
|
|
395
419
|
|
|
396
|
-
if (search_type && search_terms) || url
|
|
420
|
+
if (search_type && search_terms) || @url
|
|
397
421
|
# warn "Searching #{search_type} for #{search_terms}"
|
|
398
|
-
unless url
|
|
399
|
-
search_count += 1
|
|
400
|
-
url, title, link_text = do_search(search_type, search_terms, link_text, search_count)
|
|
422
|
+
unless @url
|
|
423
|
+
@search_count += 1
|
|
424
|
+
@url, title, @link_text = do_search(search_type, search_terms, @link_text, @search_count)
|
|
401
425
|
end
|
|
402
426
|
|
|
403
|
-
if url
|
|
404
|
-
title = SL::URL.title(url) if SL.titleize && title == ''
|
|
427
|
+
if @url
|
|
428
|
+
title = SL::URL.title(@url) if SL.titleize && title == ''
|
|
405
429
|
|
|
406
|
-
link_text = title if link_text == '' && title
|
|
430
|
+
@link_text = title if @link_text == '' && title
|
|
407
431
|
force_title = search_type =~ /def/ ? true : false
|
|
408
432
|
|
|
409
|
-
if link_only || search_type =~ /sp(ell)?/ || url == 'embed'
|
|
410
|
-
url = title if url == 'embed'
|
|
411
|
-
cursor_difference += SL.match_length - url.length
|
|
412
|
-
SL.match_length = url.length
|
|
413
|
-
SL.add_report("#{match_string} => #{url}")
|
|
414
|
-
url
|
|
415
|
-
elsif ref_title
|
|
416
|
-
unless links.key? url
|
|
417
|
-
links[url] = link_text
|
|
418
|
-
SL.add_footer SL.make_link(:ref_title, link_text, url, title: title, force_title: force_title)
|
|
433
|
+
if link_only || search_type =~ /sp(ell)?/ || @url == 'embed'
|
|
434
|
+
@url = title if @url == 'embed'
|
|
435
|
+
@cursor_difference += SL.match_length - @url.length
|
|
436
|
+
SL.match_length = @url.length
|
|
437
|
+
SL.add_report("#{@match_string} => #{@url}")
|
|
438
|
+
@url
|
|
439
|
+
elsif @ref_title
|
|
440
|
+
unless @links.key? @url
|
|
441
|
+
@links[@url] = @link_text
|
|
442
|
+
SL.add_footer SL.make_link(:ref_title, @link_text, @url, title: title, force_title: force_title)
|
|
419
443
|
end
|
|
420
|
-
delete_line = true
|
|
444
|
+
@delete_line = true
|
|
421
445
|
elsif SL.config['inline']
|
|
422
|
-
res = SL.make_link(:inline, link_text, url, title: title, force_title: force_title)
|
|
423
|
-
cursor_difference += SL.match_length - res.length
|
|
446
|
+
res = SL.make_link(:inline, @link_text, @url, title: title, force_title: force_title)
|
|
447
|
+
@cursor_difference += SL.match_length - res.length
|
|
424
448
|
SL.match_length = res.length
|
|
425
|
-
SL.add_report("#{match_string} => #{url}")
|
|
449
|
+
SL.add_report("#{@match_string} => #{@url}")
|
|
426
450
|
res
|
|
427
451
|
else
|
|
428
|
-
unless links.key? url
|
|
429
|
-
highest_marker += 1
|
|
430
|
-
links[url] = format('%<pre>s%<m>04d', pre: prefix, m: highest_marker)
|
|
431
|
-
SL.add_footer SL.make_link(:ref_title, links[url], url, title: title, force_title: force_title)
|
|
452
|
+
unless @links.key? @url
|
|
453
|
+
@highest_marker += 1
|
|
454
|
+
@links[@url] = format('%<pre>s%<m>04d', pre: @prefix, m: @highest_marker)
|
|
455
|
+
SL.add_footer SL.make_link(:ref_title, @links[@url], @url, title: title, force_title: force_title)
|
|
432
456
|
end
|
|
433
457
|
|
|
434
458
|
type = SL.config['inline'] ? :inline : :ref_link
|
|
435
|
-
res = SL.make_link(type, link_text, links[url], title: false, force_title: force_title)
|
|
436
|
-
cursor_difference += SL.match_length - res.length
|
|
459
|
+
res = SL.make_link(type, @link_text, @links[@url], title: false, force_title: force_title)
|
|
460
|
+
@cursor_difference += SL.match_length - res.length
|
|
437
461
|
SL.match_length = res.length
|
|
438
|
-
SL.add_report("#{match_string} => #{url}")
|
|
462
|
+
SL.add_report("#{@match_string} => #{@url}")
|
|
439
463
|
res
|
|
440
464
|
end
|
|
441
465
|
else
|
|
442
|
-
SL.add_error('No results', "#{search_terms} (#{match_string})")
|
|
466
|
+
SL.add_error('No results', "#{search_terms} (#{@match_string})")
|
|
443
467
|
counter_errors += 1
|
|
444
468
|
match
|
|
445
469
|
end
|
|
@@ -450,9 +474,9 @@ module SL
|
|
|
450
474
|
end
|
|
451
475
|
end
|
|
452
476
|
end
|
|
453
|
-
line_difference += 1 if delete_line
|
|
454
|
-
out.push(line) unless delete_line
|
|
455
|
-
delete_line = false
|
|
477
|
+
line_difference += 1 if @delete_line
|
|
478
|
+
out.push(line) unless @delete_line
|
|
479
|
+
@delete_line = false
|
|
456
480
|
end
|
|
457
481
|
warn "\n" unless SILENT
|
|
458
482
|
|
|
@@ -514,8 +538,8 @@ module SL
|
|
|
514
538
|
## using hostname as text without doing search
|
|
515
539
|
if SL::URL.only_url?(input.strip)
|
|
516
540
|
type = reference_link ? :ref_title : :inline
|
|
517
|
-
url, title = SL::URL.url_to_link(input.strip, type)
|
|
518
|
-
print SL.make_link(type, title, url, title: false, force_title: false)
|
|
541
|
+
@url, title = SL::URL.url_to_link(input.strip, type)
|
|
542
|
+
print SL.make_link(type, title, @url, title: false, force_title: false)
|
|
519
543
|
Process.exit
|
|
520
544
|
end
|
|
521
545
|
|
|
@@ -532,10 +556,10 @@ module SL
|
|
|
532
556
|
# input.sub!(/\+.*?$/, '').strip!
|
|
533
557
|
# end
|
|
534
558
|
|
|
535
|
-
link_text = false
|
|
559
|
+
@link_text = false
|
|
536
560
|
|
|
537
561
|
if input =~ /"(.*?)"/
|
|
538
|
-
link_text = Regexp.last_match(1)
|
|
562
|
+
@link_text = Regexp.last_match(1)
|
|
539
563
|
input.gsub!(/"(.*?)"/, '\1')
|
|
540
564
|
end
|
|
541
565
|
|
|
@@ -546,7 +570,7 @@ module SL
|
|
|
546
570
|
when /^!(\S+)\s+(.*)$/
|
|
547
571
|
type = Regexp.last_match(1)
|
|
548
572
|
link_info = Regexp.last_match(2).strip
|
|
549
|
-
link_text ||= link_info
|
|
573
|
+
@link_text ||= link_info
|
|
550
574
|
terms = link_info + additional_terms
|
|
551
575
|
terms.strip!
|
|
552
576
|
|
|
@@ -556,7 +580,7 @@ module SL
|
|
|
556
580
|
SL.config['custom_site_searches'].each do |k, v|
|
|
557
581
|
next unless type == k
|
|
558
582
|
|
|
559
|
-
link_text = terms if link_text == ''
|
|
583
|
+
@link_text = terms if @link_text == ''
|
|
560
584
|
v = parse_arguments(v, { no_restore: true })
|
|
561
585
|
if v =~ %r{^(/|http)}i
|
|
562
586
|
type = 'r'
|
|
@@ -614,10 +638,10 @@ module SL
|
|
|
614
638
|
terms = "site:#{type} #{terms}"
|
|
615
639
|
type = SL::GoogleSearch.api_key? ? 'gg' : 'g'
|
|
616
640
|
end
|
|
617
|
-
search_count ||= 0
|
|
618
|
-
search_count += 1
|
|
641
|
+
@search_count ||= 0
|
|
642
|
+
@search_count += 1
|
|
619
643
|
|
|
620
|
-
url, title, link_text = do_search(type, terms, link_text, search_count)
|
|
644
|
+
@url, title, @link_text = do_search(type, terms, @link_text, @search_count)
|
|
621
645
|
else
|
|
622
646
|
SL.add_error("Invalid search#{SL::Searches.did_you_mean(type)}", input)
|
|
623
647
|
counter_errors += 1
|
|
@@ -630,25 +654,25 @@ module SL
|
|
|
630
654
|
else
|
|
631
655
|
't'
|
|
632
656
|
end
|
|
633
|
-
link_text = input.sub(/^[tfilm]/, '')
|
|
634
|
-
url, title = SL::SocialSearch.social_handle(type, link_text)
|
|
635
|
-
link_text = title
|
|
657
|
+
@link_text = input.sub(/^[tfilm]/, '')
|
|
658
|
+
@url, title = SL::SocialSearch.social_handle(type, @link_text)
|
|
659
|
+
@link_text = title
|
|
636
660
|
else
|
|
637
|
-
link_text ||= input
|
|
638
|
-
url, title, link_text = SL.ddg(input, link_text)
|
|
661
|
+
@link_text ||= input
|
|
662
|
+
@url, title, @link_text = SL.ddg(input, @link_text)
|
|
639
663
|
end
|
|
640
664
|
|
|
641
|
-
if url
|
|
665
|
+
if @url
|
|
642
666
|
if type =~ /sp(ell)?/
|
|
643
|
-
SL.add_output(url)
|
|
667
|
+
SL.add_output(@url)
|
|
644
668
|
elsif link_only
|
|
645
|
-
SL.add_output(url)
|
|
646
|
-
elsif url == 'embed'
|
|
669
|
+
SL.add_output(@url)
|
|
670
|
+
elsif @url == 'embed'
|
|
647
671
|
SL.add_output(title)
|
|
648
672
|
else
|
|
649
673
|
type = reference_link ? :ref_title : :inline
|
|
650
674
|
|
|
651
|
-
SL.add_output SL.make_link(type, link_text, url, title: title, force_title: false)
|
|
675
|
+
SL.add_output SL.make_link(type, @link_text, @url, title: title, force_title: false)
|
|
652
676
|
SL.print_errors
|
|
653
677
|
end
|
|
654
678
|
else
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# title: Script plugin
|
|
4
|
+
# description: Load custom searches from non-ruby scripts
|
|
5
|
+
module SL
|
|
6
|
+
# Script Search
|
|
7
|
+
class ScriptSearch
|
|
8
|
+
def initialize(config)
|
|
9
|
+
@filename = config['filename']
|
|
10
|
+
@path = config['path']
|
|
11
|
+
|
|
12
|
+
%w[trigger searches name script].each do |key|
|
|
13
|
+
raise PluginError.new(%(configuration missing key "#{key}"), plugin: @filename) unless config.key?(key)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@trigger = config['trigger']
|
|
17
|
+
@searches = config['searches']
|
|
18
|
+
@name = config['name']
|
|
19
|
+
@script = find_script(config['script'])
|
|
20
|
+
|
|
21
|
+
unless File.executable?(@script)
|
|
22
|
+
raise PluginError.new(%(script "#{File.basename(@script)}" not executable\nrun `chmod a+x #{@script.shorten_path}` to correct),
|
|
23
|
+
plugin: @filename)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
def settings
|
|
28
|
+
{
|
|
29
|
+
trigger: @trigger,
|
|
30
|
+
searches: @searches
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def search(search_type, search_terms, link_text)
|
|
35
|
+
type = Shellwords.escape(search_type)
|
|
36
|
+
terms = Shellwords.escape(search_terms)
|
|
37
|
+
text = Shellwords.escape(link_text)
|
|
38
|
+
|
|
39
|
+
stdout = `#{[@script, type, terms, text].join(' ')} 2>&1`
|
|
40
|
+
|
|
41
|
+
unless $CHILD_STATUS.success?
|
|
42
|
+
raise PluginError.new(%("#{File.basename(@script)}" returned error #{$CHILD_STATUS.exitstatus}\n#{stdout}),
|
|
43
|
+
plugin: @filename)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
res = JSON.parse(stdout)
|
|
48
|
+
rescue JSON::ParserError
|
|
49
|
+
res = YAML.safe_load(stdout)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
unless res.is_a?(Hash)
|
|
53
|
+
raise PluginError.new(%(invalid results from "#{File.basename(@script)}", must be YAML or JSON string),
|
|
54
|
+
plugin: @filename)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
%w[url title link_text].each do |key|
|
|
58
|
+
unless res.key?(key)
|
|
59
|
+
raise PluginError.new(%("#{File.basename(@script)}" output missing key "#{key}"), plugin: @filename)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
[res['url'], res['title'], res['link_text']]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
SL::Searches.register @name, :search, self
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def find_script(script)
|
|
71
|
+
return script if File.exist?(File.expand_path(script))
|
|
72
|
+
|
|
73
|
+
base = File.expand_path('~/.config/searchlink/plugins')
|
|
74
|
+
first = File.join(base, script)
|
|
75
|
+
return first if File.exist?(first)
|
|
76
|
+
|
|
77
|
+
base = File.expand_path('~/.config/searchlink')
|
|
78
|
+
second = File.join(base, script)
|
|
79
|
+
return second if File.exist?(second)
|
|
80
|
+
|
|
81
|
+
raise PluginError.new(%(Script plugin script "#{script}" not found), plugin: @filename)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -31,14 +31,25 @@ module SL
|
|
|
31
31
|
## @return [Array] Single bookmark, [url, title, date]
|
|
32
32
|
##
|
|
33
33
|
def search_brave_history(term)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
base = File.expand_path('~/Library/Application Support/BraveSoftware/Brave-Browser/')
|
|
35
|
+
profiles = Dir.glob('**/History', base: base)
|
|
36
|
+
profiles.delete_if { |p| p =~ /^Snapshots/ }
|
|
37
|
+
profiles.map! { |f| File.join(base, f) }
|
|
38
|
+
|
|
39
|
+
res = false
|
|
40
|
+
|
|
41
|
+
profiles.each do |bookmarks|
|
|
42
|
+
next unless File.exist?(bookmarks)
|
|
43
|
+
|
|
44
|
+
profile = bookmarks.match(%r{Browser/([^/]+)/})[1]
|
|
45
|
+
|
|
46
|
+
SL.notify("Searching Brave History for profile #{profile}", term)
|
|
47
|
+
res = search_chromium_history(bookmarks, term)
|
|
48
|
+
|
|
49
|
+
break if res
|
|
41
50
|
end
|
|
51
|
+
|
|
52
|
+
res
|
|
42
53
|
end
|
|
43
54
|
|
|
44
55
|
## Search Edge history
|
|
@@ -66,9 +77,7 @@ module SL
|
|
|
66
77
|
break if res
|
|
67
78
|
end
|
|
68
79
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
false
|
|
80
|
+
res
|
|
72
81
|
end
|
|
73
82
|
|
|
74
83
|
## Search Chrome history
|
|
@@ -99,9 +108,7 @@ module SL
|
|
|
99
108
|
break if res
|
|
100
109
|
end
|
|
101
110
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
false
|
|
111
|
+
res
|
|
105
112
|
end
|
|
106
113
|
|
|
107
114
|
##
|
|
@@ -172,7 +179,7 @@ module SL
|
|
|
172
179
|
|
|
173
180
|
if File.exist?(bookmarks_file)
|
|
174
181
|
SL.notify('Searching Arc Bookmarks', term)
|
|
175
|
-
return
|
|
182
|
+
return search_arc_json(bookmarks_file, term)
|
|
176
183
|
end
|
|
177
184
|
|
|
178
185
|
false
|
|
@@ -204,9 +211,7 @@ module SL
|
|
|
204
211
|
break if res
|
|
205
212
|
end
|
|
206
213
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
false
|
|
214
|
+
res
|
|
210
215
|
end
|
|
211
216
|
|
|
212
217
|
##
|
|
@@ -225,18 +230,16 @@ module SL
|
|
|
225
230
|
res = false
|
|
226
231
|
|
|
227
232
|
profiles.each do |bookmarks|
|
|
228
|
-
|
|
229
|
-
profile = bookmarks.match(%r{Edge/([^/]+)/})[1]
|
|
233
|
+
next unless File.exist?(bookmarks)
|
|
230
234
|
|
|
231
|
-
|
|
232
|
-
res = search_chromium_bookmarks(bookmarks, term)
|
|
233
|
-
break if res
|
|
234
|
-
end
|
|
235
|
-
end
|
|
235
|
+
profile = bookmarks.match(%r{Edge/([^/]+)/})[1]
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
SL.notify("Searching Edge Bookmarks for profile #{profile}", term)
|
|
238
|
+
res = search_chromium_bookmarks(bookmarks, term)
|
|
239
|
+
break if res
|
|
240
|
+
end
|
|
238
241
|
|
|
239
|
-
|
|
242
|
+
res
|
|
240
243
|
end
|
|
241
244
|
|
|
242
245
|
##
|
|
@@ -264,9 +267,7 @@ module SL
|
|
|
264
267
|
end
|
|
265
268
|
end
|
|
266
269
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
false
|
|
270
|
+
res
|
|
270
271
|
end
|
|
271
272
|
|
|
272
273
|
##
|
|
@@ -277,7 +278,7 @@ module SL
|
|
|
277
278
|
##
|
|
278
279
|
## @return [Array] single bookmark [url, title, date]
|
|
279
280
|
##
|
|
280
|
-
def
|
|
281
|
+
def search_arc_json(bookmarks_file, term)
|
|
281
282
|
arc_bookmarks = JSON.parse(IO.read(bookmarks_file))
|
|
282
283
|
|
|
283
284
|
exact_match = false
|
|
@@ -341,7 +342,7 @@ module SL
|
|
|
341
342
|
|
|
342
343
|
return false if bookmarks.empty?
|
|
343
344
|
|
|
344
|
-
lastest_bookmark = bookmarks.
|
|
345
|
+
lastest_bookmark = bookmarks.min_by { |u| u[:created] }
|
|
345
346
|
|
|
346
347
|
return [lastest_bookmark[:url], lastest_bookmark[:title], lastest_bookmark[:date]]
|
|
347
348
|
end
|
data/lib/searchlink/searches.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module SL
|
|
4
|
+
# Searches and plugin registration
|
|
4
5
|
module Searches
|
|
5
6
|
class << self
|
|
6
7
|
def plugins
|
|
@@ -25,7 +26,7 @@ module SL
|
|
|
25
26
|
|
|
26
27
|
def description_for_search(search_type)
|
|
27
28
|
description = "#{search_type} search"
|
|
28
|
-
plugins[:search].
|
|
29
|
+
plugins[:search].each_value do |plugin|
|
|
29
30
|
search = plugin[:searches].select { |s| s[0].is_a?(Array) ? s[0].include?(search_type) : s[0] == search_type }
|
|
30
31
|
unless search.empty?
|
|
31
32
|
description = search[0][1]
|
|
@@ -50,7 +51,11 @@ module SL
|
|
|
50
51
|
'<tbody>']
|
|
51
52
|
|
|
52
53
|
searches.each do |s|
|
|
53
|
-
out << "<tr
|
|
54
|
+
out << "<tr>
|
|
55
|
+
<td>
|
|
56
|
+
<code>!#{s[0].is_a?(Array) ? "#{s[0][0]} (#{s[0][1..-1].join(',')})" : s[0]}
|
|
57
|
+
</code>
|
|
58
|
+
</td><td>#{s[1]}</td></tr>"
|
|
54
59
|
end
|
|
55
60
|
out.concat(['</tbody>', '</table>']).join("\n")
|
|
56
61
|
end
|
|
@@ -62,7 +67,7 @@ module SL
|
|
|
62
67
|
#
|
|
63
68
|
def available_searches
|
|
64
69
|
searches = []
|
|
65
|
-
plugins[:search].
|
|
70
|
+
plugins[:search].each_value { |plugin| searches.concat(plugin[:searches].delete_if { |s| s[1].nil? }) }
|
|
66
71
|
out = []
|
|
67
72
|
searches.each do |s|
|
|
68
73
|
out += "!#{s[0].is_a?(Array) ? "#{s[0][0]} (#{s[0][1..-1].join(',')})" : s[0]}#{s[0].spacer}#{s[1]}"
|
|
@@ -77,8 +82,8 @@ module SL
|
|
|
77
82
|
|
|
78
83
|
def all_possible_searches
|
|
79
84
|
searches = []
|
|
80
|
-
plugins[:search].
|
|
81
|
-
searches.concat(SL.config['custom_site_searches'].keys)
|
|
85
|
+
plugins[:search].each_value { |plugin| plugin[:searches].each { |s| searches.push(s[0]) } }
|
|
86
|
+
searches.concat(SL.config['custom_site_searches'].keys.sort)
|
|
82
87
|
end
|
|
83
88
|
|
|
84
89
|
def did_you_mean(term)
|
|
@@ -101,11 +106,11 @@ module SL
|
|
|
101
106
|
end
|
|
102
107
|
|
|
103
108
|
def register_plugin(title, type, klass)
|
|
104
|
-
raise
|
|
109
|
+
raise PluginError.new("Plugin has no settings method", plugin: title) unless klass.respond_to? :settings
|
|
105
110
|
|
|
106
111
|
settings = klass.settings
|
|
107
112
|
|
|
108
|
-
raise
|
|
113
|
+
raise PluginError.new("Plugin has no search method", plugin: title) unless klass.respond_to? :search
|
|
109
114
|
|
|
110
115
|
plugins[type] ||= {}
|
|
111
116
|
plugins[type][title] = {
|
|
@@ -123,6 +128,8 @@ module SL
|
|
|
123
128
|
Dir.glob(File.join(plugins_folder, '**/*.rb')).sort.each do |plugin|
|
|
124
129
|
require plugin
|
|
125
130
|
end
|
|
131
|
+
|
|
132
|
+
load_custom_scripts(plugins_folder)
|
|
126
133
|
end
|
|
127
134
|
|
|
128
135
|
return unless File.directory?(new_plugins_folder)
|
|
@@ -130,6 +137,24 @@ module SL
|
|
|
130
137
|
Dir.glob(File.join(new_plugins_folder, '**/*.rb')).sort.each do |plugin|
|
|
131
138
|
require plugin
|
|
132
139
|
end
|
|
140
|
+
|
|
141
|
+
load_custom_scripts(new_plugins_folder)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def load_custom_scripts(plugins_folder)
|
|
145
|
+
Dir.glob(File.join(plugins_folder, '**/*.{json,yml,yaml}')).each do |file|
|
|
146
|
+
ext = File.extname(file).sub(/^\./, '')
|
|
147
|
+
config = IO.read(file)
|
|
148
|
+
cfg = case ext
|
|
149
|
+
when /^y/i
|
|
150
|
+
YAML.safe_load(config)
|
|
151
|
+
else
|
|
152
|
+
JSON.parse(config)
|
|
153
|
+
end
|
|
154
|
+
cfg['filename'] = File.basename(file)
|
|
155
|
+
cfg['path'] = file.shorten_path
|
|
156
|
+
SL::ScriptSearch.new(cfg)
|
|
157
|
+
end
|
|
133
158
|
end
|
|
134
159
|
|
|
135
160
|
def do_search(search_type, search_terms, link_text, timeout: SL.config['timeout'])
|
data/lib/searchlink/semver.rb
CHANGED
|
@@ -5,14 +5,14 @@ module SL
|
|
|
5
5
|
class SemVer
|
|
6
6
|
attr_accessor :maj, :min, :patch, :pre
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
## Initialize a Semantic Version object
|
|
9
|
+
##
|
|
10
|
+
## @param version_string [String] a semantic version number
|
|
11
|
+
##
|
|
12
|
+
## @return [SemVer] SemVer object
|
|
13
|
+
##
|
|
14
14
|
def initialize(version_string)
|
|
15
|
-
raise "Invalid semantic version number: #{version_string}" unless version_string.valid_version?
|
|
15
|
+
raise VersionError.new("Invalid semantic version number: #{version_string}") unless version_string.valid_version?
|
|
16
16
|
|
|
17
17
|
@maj, @min, @patch = version_string.split(/\./)
|
|
18
18
|
@pre = nil
|
data/lib/searchlink/string.rb
CHANGED
|
@@ -488,5 +488,13 @@ module SL
|
|
|
488
488
|
def code_indent
|
|
489
489
|
split(/\n/).map { |l| " #{l}" }.join("\n")
|
|
490
490
|
end
|
|
491
|
+
|
|
492
|
+
##
|
|
493
|
+
## Shorten path by adding ~ for home directory
|
|
494
|
+
##
|
|
495
|
+
def shorten_path
|
|
496
|
+
home_directory = ENV['HOME']
|
|
497
|
+
sub(home_directory, '~')
|
|
498
|
+
end
|
|
491
499
|
end
|
|
492
500
|
end
|
data/lib/searchlink/version.rb
CHANGED
data/lib/searchlink.rb
CHANGED
|
@@ -13,10 +13,14 @@ require 'zlib'
|
|
|
13
13
|
require 'time'
|
|
14
14
|
require 'json'
|
|
15
15
|
require 'erb'
|
|
16
|
+
require 'english'
|
|
16
17
|
|
|
17
18
|
# import
|
|
18
19
|
require 'tokens' if File.exist?('lib/tokens.rb')
|
|
19
20
|
|
|
21
|
+
# import
|
|
22
|
+
require 'searchlink/exceptions'
|
|
23
|
+
|
|
20
24
|
# import
|
|
21
25
|
require 'searchlink/number'
|
|
22
26
|
|
|
@@ -65,4 +69,7 @@ require 'searchlink/output'
|
|
|
65
69
|
# import
|
|
66
70
|
require 'searchlink/which'
|
|
67
71
|
|
|
72
|
+
# import
|
|
73
|
+
require 'searchlink/script_plugin'
|
|
74
|
+
|
|
68
75
|
module Secrets; end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: searchlink
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.3.
|
|
4
|
+
version: 2.3.70
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brett Terpstra
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-08-
|
|
11
|
+
date: 2024-08-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -235,11 +235,13 @@ files:
|
|
|
235
235
|
- lib/searchlink/curl.rb
|
|
236
236
|
- lib/searchlink/curl/html.rb
|
|
237
237
|
- lib/searchlink/curl/json.rb
|
|
238
|
+
- lib/searchlink/exceptions.rb
|
|
238
239
|
- lib/searchlink/help.rb
|
|
239
240
|
- lib/searchlink/number.rb
|
|
240
241
|
- lib/searchlink/output.rb
|
|
241
242
|
- lib/searchlink/parse.rb
|
|
242
243
|
- lib/searchlink/plist.rb
|
|
244
|
+
- lib/searchlink/script_plugin.rb
|
|
243
245
|
- lib/searchlink/search.rb
|
|
244
246
|
- lib/searchlink/searches.rb
|
|
245
247
|
- lib/searchlink/searches/amazon.rb
|