searchlink 2.3.59
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 +7 -0
- data/bin/searchlink +84 -0
- data/lib/searchlink/array.rb +7 -0
- data/lib/searchlink/config.rb +230 -0
- data/lib/searchlink/curl/html.rb +482 -0
- data/lib/searchlink/curl/json.rb +90 -0
- data/lib/searchlink/curl.rb +7 -0
- data/lib/searchlink/help.rb +103 -0
- data/lib/searchlink/output.rb +270 -0
- data/lib/searchlink/parse.rb +668 -0
- data/lib/searchlink/plist.rb +213 -0
- data/lib/searchlink/search.rb +70 -0
- data/lib/searchlink/searches/amazon.rb +25 -0
- data/lib/searchlink/searches/applemusic.rb +123 -0
- data/lib/searchlink/searches/bitly.rb +50 -0
- data/lib/searchlink/searches/definition.rb +67 -0
- data/lib/searchlink/searches/duckduckgo.rb +167 -0
- data/lib/searchlink/searches/github.rb +245 -0
- data/lib/searchlink/searches/google.rb +67 -0
- data/lib/searchlink/searches/helpers/chromium.rb +318 -0
- data/lib/searchlink/searches/helpers/firefox.rb +135 -0
- data/lib/searchlink/searches/helpers/safari.rb +133 -0
- data/lib/searchlink/searches/history.rb +166 -0
- data/lib/searchlink/searches/hook.rb +77 -0
- data/lib/searchlink/searches/itunes.rb +97 -0
- data/lib/searchlink/searches/lastfm.rb +41 -0
- data/lib/searchlink/searches/lyrics.rb +91 -0
- data/lib/searchlink/searches/pinboard.rb +183 -0
- data/lib/searchlink/searches/social.rb +105 -0
- data/lib/searchlink/searches/software.rb +27 -0
- data/lib/searchlink/searches/spelling.rb +59 -0
- data/lib/searchlink/searches/spotlight.rb +28 -0
- data/lib/searchlink/searches/stackoverflow.rb +31 -0
- data/lib/searchlink/searches/tmdb.rb +52 -0
- data/lib/searchlink/searches/twitter.rb +46 -0
- data/lib/searchlink/searches/wikipedia.rb +33 -0
- data/lib/searchlink/searches/youtube.rb +48 -0
- data/lib/searchlink/searches.rb +194 -0
- data/lib/searchlink/semver.rb +140 -0
- data/lib/searchlink/string.rb +469 -0
- data/lib/searchlink/url.rb +153 -0
- data/lib/searchlink/util.rb +87 -0
- data/lib/searchlink/version.rb +93 -0
- data/lib/searchlink/which.rb +175 -0
- data/lib/searchlink.rb +66 -0
- data/lib/tokens.rb +3 -0
- metadata +299 -0
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
module SL
|
|
2
|
+
class SearchLink
|
|
3
|
+
# Parse arguments in the input string
|
|
4
|
+
#
|
|
5
|
+
# @param string [String] the string to parse
|
|
6
|
+
# @param opt [Hash] the options to parse
|
|
7
|
+
# @option opt [Boolean] :only_meta (false) whether to skip flags
|
|
8
|
+
# @option opt [Boolean] :no_restore (false) whether to restore previous config
|
|
9
|
+
# @return [String] the parsed string
|
|
10
|
+
#
|
|
11
|
+
def parse_arguments(string, opt={})
|
|
12
|
+
input = string.dup
|
|
13
|
+
return "" if input.nil?
|
|
14
|
+
|
|
15
|
+
skip_flags = opt[:only_meta] || false
|
|
16
|
+
no_restore = opt[:no_restore] || false
|
|
17
|
+
restore_prev_config unless no_restore
|
|
18
|
+
|
|
19
|
+
input.parse_flags! unless skip_flags
|
|
20
|
+
|
|
21
|
+
options = %w[debug country_code inline prefix_random include_titles remove_seo validate_links]
|
|
22
|
+
options.each do |o|
|
|
23
|
+
if input =~ /^ *#{o}:\s+(\S+)$/
|
|
24
|
+
val = Regexp.last_match(1).strip
|
|
25
|
+
val = true if val =~ /true/i
|
|
26
|
+
val = false if val =~ /false/i
|
|
27
|
+
SL.config[o] = val
|
|
28
|
+
$stderr.print "\r\033[0KGlobal config: #{o} = #{SL.config[o]}\n" unless SILENT
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
next if skip_flags
|
|
32
|
+
|
|
33
|
+
while input =~ /^#{o}:\s+(.*?)$/ || input =~ /--(no-)?#{o}/
|
|
34
|
+
next unless input =~ /--(no-)?#{o}/ && !skip_flags
|
|
35
|
+
|
|
36
|
+
unless SL.prev_config.key? o
|
|
37
|
+
SL.prev_config[o] = SL.config[o]
|
|
38
|
+
bool = Regexp.last_match(1).nil? || Regexp.last_match(1) == '' ? true : false
|
|
39
|
+
SL.config[o] = bool
|
|
40
|
+
$stderr.print "\r\033[0KLine config: #{o} = #{SL.config[o]}\n" unless SILENT
|
|
41
|
+
end
|
|
42
|
+
input.sub!(/\s?--(no-)?#{o}/, '')
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
SL.clipboard ? string : input
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Parse commands from the given input string
|
|
49
|
+
#
|
|
50
|
+
# @param input [String] the input string
|
|
51
|
+
def parse_commands(input)
|
|
52
|
+
# Handle commands like help or docs
|
|
53
|
+
return unless input.strip =~ /^!?(h(elp)?|wiki|docs?|v(er(s(ion)?)?)?|up(date|grade))$/
|
|
54
|
+
|
|
55
|
+
case input.strip
|
|
56
|
+
when /^!?help$/i
|
|
57
|
+
if SILENT
|
|
58
|
+
help_dialog # %x{open http://brettterpstra.com/projects/searchlink/}
|
|
59
|
+
else
|
|
60
|
+
$stdout.puts SL.version_check.to_s
|
|
61
|
+
$stdout.puts 'See https://github.com/ttscoff/searchlink/wiki for help'
|
|
62
|
+
end
|
|
63
|
+
print input
|
|
64
|
+
when /^!?(wiki|docs)$/i
|
|
65
|
+
warn 'Opening wiki in browser'
|
|
66
|
+
`open https://github.com/ttscoff/searchlink/wiki`
|
|
67
|
+
when /^!?v(er(s(ion)?)?)?$/
|
|
68
|
+
print "[#{SL.version_check}]"
|
|
69
|
+
when /^!?up(date|grade)$/
|
|
70
|
+
SL.update_searchlink
|
|
71
|
+
print SL.output.join('')
|
|
72
|
+
end
|
|
73
|
+
Process.exit 0
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def parse(input)
|
|
77
|
+
SL.output = []
|
|
78
|
+
return false if input.empty?
|
|
79
|
+
|
|
80
|
+
parse_arguments(input, { only_meta: true })
|
|
81
|
+
SL.originput = input.dup
|
|
82
|
+
|
|
83
|
+
parse_commands(input)
|
|
84
|
+
|
|
85
|
+
SL.config['inline'] = true if input.scan(/\]\(/).length == 1 && input.split(/\n/).length == 1
|
|
86
|
+
SL.errors = {}
|
|
87
|
+
SL.report = []
|
|
88
|
+
|
|
89
|
+
# Check for new version
|
|
90
|
+
latest_version = SL.new_version?
|
|
91
|
+
if latest_version
|
|
92
|
+
SL.add_output("<!-- v#{latest_version} available, run SearchLink on the word 'update' to install. -->")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
links = {}
|
|
96
|
+
SL.footer = []
|
|
97
|
+
counter_links = 0
|
|
98
|
+
counter_errors = 0
|
|
99
|
+
|
|
100
|
+
input.sub!(/\n?<!-- Report:.*?-->\n?/m, '')
|
|
101
|
+
input.sub!(/\n?<!-- Errors:.*?-->\n?/m, '')
|
|
102
|
+
|
|
103
|
+
input.scan(/\[(.*?)\]:\s+(.*?)\n/).each { |match| links[match[1].strip] = match[0] }
|
|
104
|
+
|
|
105
|
+
prefix = if SL.config['prefix_random']
|
|
106
|
+
if input =~ /\[(\d{4}-)\d+\]: \S+/
|
|
107
|
+
Regexp.last_match(1)
|
|
108
|
+
else
|
|
109
|
+
format('%04d-', rand(9999))
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
''
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
highest_marker = 0
|
|
116
|
+
input.scan(/^\s{,3}\[(?:#{prefix})?(\d+)\]: /).each do
|
|
117
|
+
m = Regexp.last_match
|
|
118
|
+
highest_marker = m[1].to_i if m[1].to_i > highest_marker
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
footnote_counter = 0
|
|
122
|
+
input.scan(/^\s{,3}\[\^(?:#{prefix})?fn(\d+)\]: /).each do
|
|
123
|
+
m = Regexp.last_match
|
|
124
|
+
footnote_counter = m[1].to_i if m[1].to_i > footnote_counter
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
if input =~ /\[(.*?)\]\((.*?)\)/
|
|
128
|
+
lines = input.split(/\n/)
|
|
129
|
+
out = []
|
|
130
|
+
|
|
131
|
+
total_links = input.scan(/\[(.*?)\]\((.*?)\)/).length
|
|
132
|
+
in_code_block = false
|
|
133
|
+
line_difference = 0
|
|
134
|
+
lines.each_with_index do |line, num|
|
|
135
|
+
SL.line_num = num - line_difference
|
|
136
|
+
cursor_difference = 0
|
|
137
|
+
# ignore links in code blocks
|
|
138
|
+
if line =~ /^( {4,}|\t+)[^*+\-]/
|
|
139
|
+
out.push(line)
|
|
140
|
+
next
|
|
141
|
+
end
|
|
142
|
+
if line =~ /^[~`]{3,}/
|
|
143
|
+
if in_code_block
|
|
144
|
+
in_code_block = false
|
|
145
|
+
out.push(line)
|
|
146
|
+
next
|
|
147
|
+
else
|
|
148
|
+
in_code_block = true
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
if in_code_block
|
|
152
|
+
out.push(line)
|
|
153
|
+
next
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
delete_line = false
|
|
157
|
+
|
|
158
|
+
search_count = 0
|
|
159
|
+
|
|
160
|
+
line.gsub!(/\[(.*?)\]\((.*?)\)/) do |match|
|
|
161
|
+
this_match = Regexp.last_match
|
|
162
|
+
SL.match_column = this_match.begin(0) - cursor_difference
|
|
163
|
+
match_string = this_match.to_s
|
|
164
|
+
SL.match_length = match_string.length
|
|
165
|
+
match_before = this_match.pre_match
|
|
166
|
+
|
|
167
|
+
invalid_search = false
|
|
168
|
+
ref_title = false
|
|
169
|
+
|
|
170
|
+
if match_before.scan(/(^|[^\\])`/).length.odd?
|
|
171
|
+
SL.add_report("Match '#{match_string}' within an inline code block")
|
|
172
|
+
invalid_search = true
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
counter_links += 1
|
|
176
|
+
unless SILENT
|
|
177
|
+
$stderr.print("\033[0K\rProcessed: #{counter_links} of #{total_links}, #{counter_errors} errors. ")
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
link_text = this_match[1] || ''
|
|
181
|
+
link_info = parse_arguments(this_match[2].strip).strip || ''
|
|
182
|
+
|
|
183
|
+
if link_text.strip == '' && link_info =~ /".*?"/
|
|
184
|
+
link_info.gsub!(/"(.*?)"/) do
|
|
185
|
+
m = Regexp.last_match(1)
|
|
186
|
+
link_text = m if link_text == ''
|
|
187
|
+
%("#")
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
link_info.gsub!(/<(.*?)>/) do
|
|
192
|
+
%(%22#{Regexp.last_match(1)}%22)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
if link_info.strip =~ /:$/ && line.strip == match
|
|
196
|
+
ref_title = true
|
|
197
|
+
link_info.sub!(/\s*:\s*$/, '')
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
unless !link_text.empty? || !link_info.sub(/^[!\^]\S+/, '').strip.empty?
|
|
201
|
+
SL.add_error('No input', match)
|
|
202
|
+
counter_errors += 1
|
|
203
|
+
invalid_search = true
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
if link_info =~ /^!(\S+)/
|
|
207
|
+
search_type = Regexp.last_match(1)
|
|
208
|
+
unless SL::Searches.valid_search?(search_type) || search_type =~ /^(\S+\.)+\S+$/
|
|
209
|
+
SL.add_error("Invalid search#{SL::Searches.did_you_mean(search_type)}", match)
|
|
210
|
+
invalid_search = true
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
if invalid_search
|
|
215
|
+
match
|
|
216
|
+
elsif link_info =~ /^\^(.+)/
|
|
217
|
+
m = Regexp.last_match
|
|
218
|
+
if m[1].nil? || m[1] == ''
|
|
219
|
+
match
|
|
220
|
+
else
|
|
221
|
+
note = m[1].strip
|
|
222
|
+
footnote_counter += 1
|
|
223
|
+
ref = if !link_text.empty? && link_text.scan(/\s/).empty?
|
|
224
|
+
link_text
|
|
225
|
+
else
|
|
226
|
+
format('%<p>sfn%<c>04d', p: prefix, c: footnote_counter)
|
|
227
|
+
end
|
|
228
|
+
SL.add_footer "[^#{ref}]: #{note}"
|
|
229
|
+
res = "[^#{ref}]"
|
|
230
|
+
cursor_difference += (SL.match_length - res.length)
|
|
231
|
+
SL.match_length = res.length
|
|
232
|
+
SL.add_report("#{match_string} => Footnote #{ref}")
|
|
233
|
+
res
|
|
234
|
+
end
|
|
235
|
+
# Handle [](URL) and [%](URL), filling in title
|
|
236
|
+
elsif (link_text == '' || link_text == '%') && SL::URL.url?(link_info)
|
|
237
|
+
url = link_info
|
|
238
|
+
title = SL::URL.title(link_info)
|
|
239
|
+
link_text = title
|
|
240
|
+
|
|
241
|
+
if ref_title
|
|
242
|
+
unless links.key? url
|
|
243
|
+
links[url] = link_text
|
|
244
|
+
SL.add_footer SL.make_link(:ref_title, link_text, url, title: title, force_title: false)
|
|
245
|
+
end
|
|
246
|
+
delete_line = true
|
|
247
|
+
elsif SL.config['inline']
|
|
248
|
+
res = SL.make_link(:inline, link_text, url, title: title, force_title: false)
|
|
249
|
+
cursor_difference += SL.match_length - res.length
|
|
250
|
+
SL.match_length = res.length
|
|
251
|
+
SL.add_report("#{match_string} => #{url}")
|
|
252
|
+
res
|
|
253
|
+
else
|
|
254
|
+
unless links.key? url
|
|
255
|
+
highest_marker += 1
|
|
256
|
+
links[url] = format('%<pre>s%<m>04d', pre: prefix, m: highest_marker)
|
|
257
|
+
SL.add_footer SL.make_link(:ref_title, links[url], url, title: title, force_title: false)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
type = SL.config['inline'] ? :inline : :ref_link
|
|
261
|
+
res = SL.make_link(type, link_text, links[url], title: false, force_title: false)
|
|
262
|
+
cursor_difference += SL.match_length - res.length
|
|
263
|
+
SL.match_length = res.length
|
|
264
|
+
SL.add_report("#{match_string} => #{url}")
|
|
265
|
+
res
|
|
266
|
+
end
|
|
267
|
+
elsif (link_text == '' && link_info == '') || SL::URL.url?(link_info)
|
|
268
|
+
SL.add_error('Invalid search', match) unless SL::URL.url?(link_info)
|
|
269
|
+
match
|
|
270
|
+
else
|
|
271
|
+
link_info = link_text if !link_text.empty? && link_info == ''
|
|
272
|
+
|
|
273
|
+
search_type = ''
|
|
274
|
+
search_terms = ''
|
|
275
|
+
link_only = false
|
|
276
|
+
SL.clipboard = false
|
|
277
|
+
SL.titleize = SL.config['empty_uses_page_title']
|
|
278
|
+
|
|
279
|
+
if link_info =~ /^(?:[!\^](\S+))\s*(.*)$/
|
|
280
|
+
m = Regexp.last_match
|
|
281
|
+
|
|
282
|
+
search_type = m[1].nil? ? (SL::GoogleSearch.test_for_key ? 'gg' : 'g') : m[1]
|
|
283
|
+
|
|
284
|
+
search_terms = m[2].gsub(/(^["']|["']$)/, '')
|
|
285
|
+
search_terms.strip!
|
|
286
|
+
|
|
287
|
+
# if the link text is just '%' replace with title regardless of config settings
|
|
288
|
+
if link_text == '%' && search_terms && !search_terms.empty?
|
|
289
|
+
SL.titleize = true
|
|
290
|
+
link_text = ''
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
search_terms = link_text if search_terms == ''
|
|
294
|
+
|
|
295
|
+
# if the input starts with a +, append it to the link text as the search terms
|
|
296
|
+
search_terms = "#{link_text} #{search_terms.strip.sub(/^\+\s*/, '')}" if search_terms.strip =~ /^\+[^+]/
|
|
297
|
+
|
|
298
|
+
# if the end of input contain "^", copy to clipboard instead of STDOUT
|
|
299
|
+
SL.clipboard = true if search_terms =~ /(!!)?\^(!!)?$/
|
|
300
|
+
|
|
301
|
+
# if the end of input contains "!!", only print the url
|
|
302
|
+
link_only = true if search_terms =~ /!!\^?$/
|
|
303
|
+
|
|
304
|
+
search_terms.sub!(/(!!)?\^?(!!)?$/,"")
|
|
305
|
+
|
|
306
|
+
elsif link_info =~ /^!/
|
|
307
|
+
search_word = link_info.match(/^!(\S+)/)
|
|
308
|
+
|
|
309
|
+
if search_word && SL::Searches.valid_search?(search_word[1])
|
|
310
|
+
search_type = search_word[1] unless search_word.nil?
|
|
311
|
+
search_terms = link_text
|
|
312
|
+
elsif search_word && search_word[1] =~ /^(\S+\.)+\S+$/
|
|
313
|
+
search_type = SL::GoogleSearch.test_for_key ? 'gg' : 'g'
|
|
314
|
+
puts SL::GoogleSearch.test_for_key
|
|
315
|
+
search_terms = "site:#{search_word[1]} #{link_text}"
|
|
316
|
+
else
|
|
317
|
+
SL.add_error("Invalid search#{SL::Searches.did_you_mean(search_word[1])}", match)
|
|
318
|
+
search_type = false
|
|
319
|
+
search_terms = false
|
|
320
|
+
end
|
|
321
|
+
elsif link_text && !link_text.empty? && (!link_info || link_info.empty?)
|
|
322
|
+
search_type = SL::GoogleSearch.test_for_key ? 'gg' : 'g'
|
|
323
|
+
search_terms = link_text
|
|
324
|
+
elsif link_info && !link_info.empty?
|
|
325
|
+
search_type = SL::GoogleSearch.test_for_key ? 'gg' : 'g'
|
|
326
|
+
search_terms = link_info
|
|
327
|
+
else
|
|
328
|
+
SL.add_error('Invalid search', match)
|
|
329
|
+
search_type = false
|
|
330
|
+
search_terms = false
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
if search_type && !search_terms.empty?
|
|
334
|
+
SL.config['custom_site_searches'].each do |k, v|
|
|
335
|
+
next unless search_type == k
|
|
336
|
+
|
|
337
|
+
link_text = search_terms if !SL.titleize && link_text == ''
|
|
338
|
+
v = parse_arguments(v, { no_restore: true })
|
|
339
|
+
if v =~ %r{^(/|http)}i
|
|
340
|
+
search_type = 'r'
|
|
341
|
+
tokens = v.scan(/\$term\d+[ds]?/).sort.uniq
|
|
342
|
+
|
|
343
|
+
if !tokens.empty?
|
|
344
|
+
highest_token = 0
|
|
345
|
+
tokens.each do |token|
|
|
346
|
+
if token =~ /(\d+)[ds]?$/ && Regexp.last_match(1).to_i > highest_token
|
|
347
|
+
highest_token = Regexp.last_match(1).to_i
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
terms_p = search_terms.split(/ +/)
|
|
351
|
+
if terms_p.length > highest_token
|
|
352
|
+
remainder = terms_p[highest_token - 1..-1].join(' ')
|
|
353
|
+
terms_p = terms_p[0..highest_token - 2]
|
|
354
|
+
terms_p.push(remainder)
|
|
355
|
+
end
|
|
356
|
+
tokens.each do |t|
|
|
357
|
+
next unless t =~ /(\d+)[ds]?$/
|
|
358
|
+
|
|
359
|
+
int = Regexp.last_match(1).to_i - 1
|
|
360
|
+
replacement = terms_p[int]
|
|
361
|
+
case t
|
|
362
|
+
when /d$/
|
|
363
|
+
replacement.downcase!
|
|
364
|
+
re_down = ''
|
|
365
|
+
when /s$/
|
|
366
|
+
replacement.slugify!
|
|
367
|
+
re_down = ''
|
|
368
|
+
else
|
|
369
|
+
re_down = '(?!d|s)'
|
|
370
|
+
end
|
|
371
|
+
v.gsub!(/#{Regexp.escape(t) + re_down}/, replacement.url_encode)
|
|
372
|
+
end
|
|
373
|
+
search_terms = v
|
|
374
|
+
else
|
|
375
|
+
search_terms = v.gsub(/\$term[ds]?/i) do |mtch|
|
|
376
|
+
search_terms.downcase! if mtch =~ /d$/i
|
|
377
|
+
search_terms.slugify! if mtch =~ /s$/i
|
|
378
|
+
search_terms.url_encode
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
else
|
|
382
|
+
search_type = SL::GoogleSearch.test_for_key ? 'gg' : 'g'
|
|
383
|
+
search_terms = "site:#{v} #{search_terms}"
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
break
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
if (search_type && search_terms) || url
|
|
391
|
+
# warn "Searching #{search_type} for #{search_terms}"
|
|
392
|
+
if (!url)
|
|
393
|
+
search_count += 1
|
|
394
|
+
url, title, link_text = do_search(search_type, search_terms, link_text, search_count)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
if url
|
|
398
|
+
title = SL::URL.title(url) if SL.titleize && title == ''
|
|
399
|
+
|
|
400
|
+
link_text = title if link_text == '' && title
|
|
401
|
+
force_title = search_type =~ /def/ ? true : false
|
|
402
|
+
|
|
403
|
+
if link_only || search_type =~ /sp(ell)?/ || url == 'embed'
|
|
404
|
+
url = title if url == 'embed'
|
|
405
|
+
cursor_difference += SL.match_length - url.length
|
|
406
|
+
SL.match_length = url.length
|
|
407
|
+
SL.add_report("#{match_string} => #{url}")
|
|
408
|
+
url
|
|
409
|
+
elsif ref_title
|
|
410
|
+
unless links.key? url
|
|
411
|
+
links[url] = link_text
|
|
412
|
+
SL.add_footer SL.make_link(:ref_title, link_text, url, title: title, force_title: force_title)
|
|
413
|
+
end
|
|
414
|
+
delete_line = true
|
|
415
|
+
elsif SL.config['inline']
|
|
416
|
+
res = SL.make_link(:inline, link_text, url, title: title, force_title: force_title)
|
|
417
|
+
cursor_difference += SL.match_length - res.length
|
|
418
|
+
SL.match_length = res.length
|
|
419
|
+
SL.add_report("#{match_string} => #{url}")
|
|
420
|
+
res
|
|
421
|
+
else
|
|
422
|
+
unless links.key? url
|
|
423
|
+
highest_marker += 1
|
|
424
|
+
links[url] = format('%<pre>s%<m>04d', pre: prefix, m: highest_marker)
|
|
425
|
+
SL.add_footer SL.make_link(:ref_title, links[url], url, title: title, force_title: force_title)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
type = SL.config['inline'] ? :inline : :ref_link
|
|
429
|
+
res = SL.make_link(type, link_text, links[url], title: false, force_title: force_title)
|
|
430
|
+
cursor_difference += SL.match_length - res.length
|
|
431
|
+
SL.match_length = res.length
|
|
432
|
+
SL.add_report("#{match_string} => #{url}")
|
|
433
|
+
res
|
|
434
|
+
end
|
|
435
|
+
else
|
|
436
|
+
SL.add_error('No results', "#{search_terms} (#{match_string})")
|
|
437
|
+
counter_errors += 1
|
|
438
|
+
match
|
|
439
|
+
end
|
|
440
|
+
else
|
|
441
|
+
SL.add_error('Invalid search', match)
|
|
442
|
+
counter_errors += 1
|
|
443
|
+
match
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
line_difference += 1 if delete_line
|
|
448
|
+
out.push(line) unless delete_line
|
|
449
|
+
delete_line = false
|
|
450
|
+
end
|
|
451
|
+
warn "\n" unless SILENT
|
|
452
|
+
|
|
453
|
+
input = out.delete_if { |l| l.strip =~ /^<!--DELETE-->$/ }.join("\n")
|
|
454
|
+
|
|
455
|
+
if SL.config['inline']
|
|
456
|
+
SL.add_output "#{input}\n"
|
|
457
|
+
SL.add_output "\n#{SL.print_footer}" unless SL.footer.empty?
|
|
458
|
+
elsif SL.footer.empty?
|
|
459
|
+
SL.add_output input
|
|
460
|
+
else
|
|
461
|
+
last_line = input.strip.split(/\n/)[-1]
|
|
462
|
+
case last_line
|
|
463
|
+
when /^\[.*?\]: http/
|
|
464
|
+
SL.add_output "#{input.rstrip}\n"
|
|
465
|
+
when /^\[\^.*?\]: /
|
|
466
|
+
SL.add_output input.rstrip
|
|
467
|
+
else
|
|
468
|
+
SL.add_output "#{input}\n\n"
|
|
469
|
+
end
|
|
470
|
+
SL.add_output "#{SL.print_footer}\n\n"
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
SL.line_num = nil
|
|
474
|
+
SL.add_report("Processed: #{total_links} links, #{counter_errors} errors.")
|
|
475
|
+
SL.print_report
|
|
476
|
+
SL.print_errors
|
|
477
|
+
else
|
|
478
|
+
link_only = false
|
|
479
|
+
SL.clipboard = false
|
|
480
|
+
|
|
481
|
+
res = parse_arguments(input.strip!).strip
|
|
482
|
+
input = res.nil? ? input.strip : res
|
|
483
|
+
|
|
484
|
+
# if the end of input contain "^", copy to clipboard instead of STDOUT
|
|
485
|
+
SL.clipboard = true if input =~ /\^[!~:\s]*$/
|
|
486
|
+
|
|
487
|
+
# if the end of input contains "!!", only print the url
|
|
488
|
+
link_only = true if input =~ /!![\^~:\s]*$/
|
|
489
|
+
|
|
490
|
+
reference_link = input =~ /:([!\^~\s]*)$/
|
|
491
|
+
|
|
492
|
+
# if end of input contains ~, pull url from clipboard
|
|
493
|
+
if input =~ /~[:\^!\s]*$/
|
|
494
|
+
input.sub!(/[:!\^\s~]*$/, '')
|
|
495
|
+
clipboard = `__CF_USER_TEXT_ENCODING=$UID:0x8000100:0x8000100 pbpaste`.strip
|
|
496
|
+
if SL::URL.url?(clipboard)
|
|
497
|
+
type = reference_link ? :ref_title : :inline
|
|
498
|
+
print SL.make_link(type, input.strip, clipboard)
|
|
499
|
+
else
|
|
500
|
+
print SL.originput
|
|
501
|
+
end
|
|
502
|
+
Process.exit
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
input.sub!(/[:!\^\s~]*$/, '')
|
|
506
|
+
|
|
507
|
+
## Maybe if input is just a URL, convert it to a link
|
|
508
|
+
## using hostname as text without doing search
|
|
509
|
+
if SL::URL.only_url?(input.strip)
|
|
510
|
+
type = reference_link ? :ref_title : :inline
|
|
511
|
+
url, title = SL::URL.url_to_link(input.strip, type)
|
|
512
|
+
print SL.make_link(type, title, url, title: false, force_title: false)
|
|
513
|
+
Process.exit
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
# check for additional search terms in parenthesis
|
|
517
|
+
additional_terms = ''
|
|
518
|
+
if input =~ /\((.*?)\)/
|
|
519
|
+
additional_terms = " #{Regexp.last_match(1).strip}"
|
|
520
|
+
input.sub!(/\(.*?\)/, '')
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
# Maybe detect "search + addition terms" and remove additional terms from link text?
|
|
524
|
+
# if input =~ /\+(.+?)$/
|
|
525
|
+
# additional_terms = "#{additional_terms} #{Regexp.last_match(1).strip}"
|
|
526
|
+
# input.sub!(/\+.*?$/, '').strip!
|
|
527
|
+
# end
|
|
528
|
+
|
|
529
|
+
link_text = false
|
|
530
|
+
|
|
531
|
+
if input =~ /"(.*?)"/
|
|
532
|
+
link_text = Regexp.last_match(1)
|
|
533
|
+
input.gsub!(/"(.*?)"/, '\1')
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
# remove quotes from terms, just in case
|
|
537
|
+
# input.sub!(/^(!\S+)?\s*(["'])(.*?)\2([\!\^]+)?$/, "\\1 \\3\\4")
|
|
538
|
+
|
|
539
|
+
case input
|
|
540
|
+
when /^!(\S+)\s+(.*)$/
|
|
541
|
+
type = Regexp.last_match(1)
|
|
542
|
+
link_info = Regexp.last_match(2).strip
|
|
543
|
+
link_text ||= link_info
|
|
544
|
+
terms = link_info + additional_terms
|
|
545
|
+
terms.strip!
|
|
546
|
+
|
|
547
|
+
if SL::Searches.valid_search?(type) || type =~ /^(\S+\.)+\S+$/
|
|
548
|
+
if type && terms && !terms.empty?
|
|
549
|
+
# Iterate through custom searches for a match, perform search if matched
|
|
550
|
+
SL.config['custom_site_searches'].each do |k, v|
|
|
551
|
+
next unless type == k
|
|
552
|
+
|
|
553
|
+
link_text = terms if link_text == ''
|
|
554
|
+
v = parse_arguments(v, { no_restore: true })
|
|
555
|
+
if v =~ %r{^(/|http)}i
|
|
556
|
+
type = 'r'
|
|
557
|
+
tokens = v.scan(/\$term\d+[ds]?/).sort.uniq
|
|
558
|
+
|
|
559
|
+
if !tokens.empty?
|
|
560
|
+
highest_token = 0
|
|
561
|
+
tokens.each do |token|
|
|
562
|
+
t = Regexp.last_match(1)
|
|
563
|
+
highest_token = t.to_i if token =~ /(\d+)d?$/ && t.to_i > highest_token
|
|
564
|
+
end
|
|
565
|
+
terms_p = terms.split(/ +/)
|
|
566
|
+
if terms_p.length > highest_token
|
|
567
|
+
remainder = terms_p[highest_token - 1..].join(' ')
|
|
568
|
+
terms_p = terms_p[0..highest_token - 2]
|
|
569
|
+
terms_p.push(remainder)
|
|
570
|
+
end
|
|
571
|
+
tokens.each do |t|
|
|
572
|
+
next unless t =~ /(\d+)d?$/
|
|
573
|
+
|
|
574
|
+
int = Regexp.last_match(1).to_i - 1
|
|
575
|
+
replacement = terms_p[int]
|
|
576
|
+
|
|
577
|
+
re_down = case t
|
|
578
|
+
when /d$/
|
|
579
|
+
replacement.downcase!
|
|
580
|
+
''
|
|
581
|
+
when /s$/
|
|
582
|
+
replacement.slugify!
|
|
583
|
+
''
|
|
584
|
+
else
|
|
585
|
+
'(?!d|s)'
|
|
586
|
+
end
|
|
587
|
+
v.gsub!(/#{Regexp.escape(t) + re_down}/, replacement.url_encode)
|
|
588
|
+
end
|
|
589
|
+
terms = v
|
|
590
|
+
else
|
|
591
|
+
terms = v.gsub(/\$term[ds]?/i) do |mtch|
|
|
592
|
+
terms.downcase! if mtch =~ /d$/i
|
|
593
|
+
terms.slugify! if mtch =~ /s$/i
|
|
594
|
+
terms.url_encode
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
else
|
|
598
|
+
type = SL::GoogleSearch.test_for_key ? 'gg' : 'g'
|
|
599
|
+
terms = "site:#{v} #{terms}"
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
break
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
# if contains TLD, use site-specific search
|
|
607
|
+
if type =~ /^(\S+\.)+\S+$/
|
|
608
|
+
terms = "site:#{type} #{terms}"
|
|
609
|
+
type = SL::GoogleSearch.test_for_key ? 'gg' : 'g'
|
|
610
|
+
end
|
|
611
|
+
search_count ||= 0
|
|
612
|
+
search_count += 1
|
|
613
|
+
|
|
614
|
+
url, title, link_text = do_search(type, terms, link_text, search_count)
|
|
615
|
+
else
|
|
616
|
+
SL.add_error("Invalid search#{SL::Searches.did_you_mean(type)}", input)
|
|
617
|
+
counter_errors += 1
|
|
618
|
+
end
|
|
619
|
+
# Social handle expansion
|
|
620
|
+
when /^([tfilm])?@(\S+)\s*$/
|
|
621
|
+
type = Regexp.last_match(1)
|
|
622
|
+
unless type
|
|
623
|
+
# If contains @ mid-handle, use Mastodon
|
|
624
|
+
if Regexp.last_match(2) =~ /[a-z0-9_]@[a-z0-9_.]+/i
|
|
625
|
+
type = 'm'
|
|
626
|
+
else
|
|
627
|
+
type = 't'
|
|
628
|
+
end
|
|
629
|
+
end
|
|
630
|
+
link_text = input.sub(/^[tfilm]/, '')
|
|
631
|
+
url, title = SL::SocialSearch.social_handle(type, link_text)
|
|
632
|
+
link_text = title
|
|
633
|
+
else
|
|
634
|
+
link_text ||= input
|
|
635
|
+
url, title, link_text = SL.ddg(input, link_text)
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
if url
|
|
639
|
+
if type =~ /sp(ell)?/
|
|
640
|
+
SL.add_output(url)
|
|
641
|
+
elsif link_only
|
|
642
|
+
SL.add_output(url)
|
|
643
|
+
elsif url == 'embed'
|
|
644
|
+
SL.add_output(title)
|
|
645
|
+
else
|
|
646
|
+
type = reference_link ? :ref_title : :inline
|
|
647
|
+
|
|
648
|
+
SL.add_output SL.make_link(type, link_text, url, title: title, force_title: false)
|
|
649
|
+
SL.print_errors
|
|
650
|
+
end
|
|
651
|
+
else
|
|
652
|
+
SL.add_error('No results', title)
|
|
653
|
+
SL.add_output SL.originput.chomp
|
|
654
|
+
SL.print_errors
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
if SL.clipboard
|
|
658
|
+
if SL.output == SL.originput
|
|
659
|
+
warn 'No results found'
|
|
660
|
+
else
|
|
661
|
+
`echo #{Shellwords.escape(SL.output.join(''))}|tr -d "\n"|pbcopy`
|
|
662
|
+
warn 'Results in clipboard'
|
|
663
|
+
end
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
end
|
|
667
|
+
end
|
|
668
|
+
end
|