searchlink 2.3.86 → 2.3.88
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/bin/searchlink +20 -19
- data/lib/searchlink/config.rb +1 -1
- data/lib/searchlink/curl/html.rb +24 -21
- data/lib/searchlink/curl/json.rb +5 -7
- data/lib/searchlink/help.rb +6 -2
- data/lib/searchlink/output.rb +28 -16
- data/lib/searchlink/parse.rb +425 -405
- data/lib/searchlink/plist/generator.rb +178 -0
- data/lib/searchlink/plist/parser.rb +263 -0
- data/lib/searchlink/plist/version.rb +5 -0
- data/lib/searchlink/plist.rb +12 -202
- data/lib/searchlink/script_plugin.rb +1 -3
- data/lib/searchlink/search.rb +1 -5
- data/lib/searchlink/searches/duckduckgo.rb +2 -1
- data/lib/searchlink/searches/google.rb +4 -2
- data/lib/searchlink/searches/history.rb +5 -5
- data/lib/searchlink/searches/linkding.rb +2 -2
- data/lib/searchlink/searches/popup.rb +14 -15
- data/lib/searchlink/searches/setapp.rb +3 -1
- data/lib/searchlink/searches/shortener.rb +14 -14
- data/lib/searchlink/searches/shorteners/bitly.rb +2 -1
- data/lib/searchlink/searches/shorteners/tinyurl.rb +2 -1
- data/lib/searchlink/searches/social.rb +33 -28
- data/lib/searchlink/searches/twitter.rb +11 -12
- data/lib/searchlink/searches.rb +17 -17
- data/lib/searchlink/string.rb +76 -50
- data/lib/searchlink/url.rb +5 -2
- data/lib/searchlink/util.rb +13 -0
- data/lib/searchlink/version.rb +4 -4
- data/lib/searchlink.rb +3 -3
- metadata +5 -2
data/lib/searchlink/parse.rb
CHANGED
@@ -4,7 +4,7 @@ module SL
|
|
4
4
|
class SearchLink
|
5
5
|
# Confirm a URL with a popup if requested
|
6
6
|
def confirmed?(url)
|
7
|
-
return true
|
7
|
+
return true if !SL.config["confirm"] || NO_CONFIRM
|
8
8
|
|
9
9
|
SL::Shortener.confirm?(url)
|
10
10
|
end
|
@@ -19,36 +19,23 @@ module SL
|
|
19
19
|
|
20
20
|
parse_commands(input)
|
21
21
|
|
22
|
-
SL.config["inline"] = true if input.scan(
|
22
|
+
SL.config["inline"] = true if input.scan("](").length == 1 && input.split("\n").length == 1
|
23
23
|
SL.errors = {}
|
24
24
|
SL.report = []
|
25
25
|
SL.shortener = :none
|
26
26
|
|
27
27
|
# Check for new version
|
28
28
|
latest_version = SL.new_version?
|
29
|
-
if latest_version
|
30
|
-
SL.add_output("<!-- v#{latest_version} available, run SearchLink on the word 'update' to install. -->")
|
31
|
-
end
|
29
|
+
SL.add_output("<!-- v#{latest_version} available, run SearchLink on the word 'update' to install. -->") if latest_version
|
32
30
|
|
33
|
-
@links = {}
|
34
31
|
SL.footer = []
|
35
|
-
counter_links = 0
|
36
|
-
counter_errors = 0
|
37
32
|
|
38
33
|
input.sub!(/\n?<!-- Report:.*?-->\n?/m, "")
|
39
34
|
input.sub!(/\n?<!-- Errors:.*?-->\n?/m, "")
|
40
35
|
|
41
|
-
|
36
|
+
@links = input.scan_links
|
42
37
|
|
43
|
-
@prefix =
|
44
|
-
if input =~ /\[(\d{4}-)\d+\]: \S+/
|
45
|
-
Regexp.last_match(1)
|
46
|
-
else
|
47
|
-
format("%04d-", rand(9999))
|
48
|
-
end
|
49
|
-
else
|
50
|
-
""
|
51
|
-
end
|
38
|
+
@prefix = determine_prefix(input)
|
52
39
|
|
53
40
|
@highest_marker = 0
|
54
41
|
input.scan(/^\s{,3}\[(?:#{@prefix})?(\d+)\]: /).each do
|
@@ -63,30 +50,33 @@ module SL
|
|
63
50
|
end
|
64
51
|
|
65
52
|
if SL.config["complete_bare"]
|
53
|
+
# match all URLs not preceded by a ( or : or <, and are followed by a space or newline
|
66
54
|
rx = %r{(?ix-m)(?<!\(|:\s|<)(?:
|
67
55
|
(?:https?://)(?:[\da-z.-]+)\.(?:[a-z.]{2,6})
|
68
|
-
(?:[/\w\d.\-()_
|
56
|
+
(?:[/\w\d.\-()_+=?&%]*?(?=[\s\n]|$))
|
69
57
|
)}
|
58
|
+
# replace with [%](url)
|
70
59
|
input.gsub!(rx) do
|
71
60
|
url_match = Regexp.last_match
|
72
61
|
url_match.pre_match =~ /!\S+ +$/ ? url_match[0] : "[%](#{url_match[0]})"
|
73
62
|
end
|
74
63
|
end
|
75
64
|
|
65
|
+
# Handle multi-line links in the form of [\ntext\n](url)
|
76
66
|
if input =~ /\[\n(.*?\n)+\]\((.*?)?\)/
|
77
67
|
input.gsub!(/\[\n(((\s*(?:[-+*]|\d+\.)?\s+)*(!\S+ +)?(.*?))\n)+\]\((!\S+.*?)?\)/) do
|
78
68
|
m = Regexp.last_match
|
79
|
-
lines = m[0].split(
|
69
|
+
lines = m[0].split("\n")
|
80
70
|
lines = lines[1..-2]
|
81
71
|
lines.map do |l|
|
82
72
|
el_rx = /(\s*(?:[-+*]|\d+\.)?\s+)?(!\S+ )?(\w.*?)$/
|
83
73
|
if l =~ el_rx
|
84
74
|
els = l.match(el_rx)
|
85
75
|
search = if els[2]
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
76
|
+
els[2].strip
|
77
|
+
else
|
78
|
+
m[6] || "!g"
|
79
|
+
end
|
90
80
|
"#{els[1]}[#{els[3].strip}](#{search})"
|
91
81
|
else
|
92
82
|
l
|
@@ -97,439 +87,470 @@ module SL
|
|
97
87
|
|
98
88
|
# Handle links in the form of [text](url) or [text](url "title")
|
99
89
|
if input =~ /\[(.*?)\]\((.*?)\)/
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
line_difference = 0
|
106
|
-
lines.each_with_index do |line, num|
|
107
|
-
SL.line_num = num - line_difference
|
108
|
-
@cursor_difference = 0
|
109
|
-
# ignore links in code blocks
|
110
|
-
if line =~ /^(( {4,}|\t+)[^*+-])/
|
111
|
-
out.push(line)
|
112
|
-
next
|
113
|
-
end
|
114
|
-
if line =~ /^\s*[~`]{3,}/
|
115
|
-
if in_code_block
|
116
|
-
in_code_block = false
|
117
|
-
out.push(line)
|
118
|
-
next
|
119
|
-
else
|
120
|
-
in_code_block = true
|
121
|
-
end
|
122
|
-
end
|
123
|
-
if in_code_block
|
124
|
-
out.push(line)
|
125
|
-
next
|
126
|
-
end
|
90
|
+
parse_brackets(input)
|
91
|
+
else # Assume single line input
|
92
|
+
parse_single_line(input)
|
93
|
+
end
|
94
|
+
end
|
127
95
|
|
128
|
-
|
96
|
+
private
|
129
97
|
|
130
|
-
|
98
|
+
# Determine the prefix for footnotes
|
99
|
+
def determine_prefix(input)
|
100
|
+
if SL.config["prefix_random"]
|
101
|
+
if input =~ /\[(\d{4}-)\d+\]: \S+/
|
102
|
+
Regexp.last_match(1)
|
103
|
+
else
|
104
|
+
format("%04d-", rand(9999))
|
105
|
+
end
|
106
|
+
else
|
107
|
+
""
|
108
|
+
end
|
109
|
+
end
|
131
110
|
|
132
|
-
|
133
|
-
|
111
|
+
def parse_single_line(input)
|
112
|
+
link_only = false
|
113
|
+
SL.clipboard = false
|
134
114
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
match_before = this_match.pre_match
|
115
|
+
res = parse_arguments(input.strip!).strip
|
116
|
+
input = res.nil? ? input.strip : res
|
117
|
+
query, input = input.extract_query({})
|
139
118
|
|
140
|
-
|
141
|
-
|
119
|
+
# if the end of input contain "^", copy to clipboard instead of STDOUT
|
120
|
+
SL.clipboard = true if input =~ /\^[!~:\s]*$/
|
142
121
|
|
143
|
-
|
144
|
-
|
145
|
-
invalid_search = true
|
146
|
-
end
|
122
|
+
# if the end of input contains "!!", only print the url
|
123
|
+
link_only = true if input =~ /!![\^~:\s]*$/
|
147
124
|
|
148
|
-
|
149
|
-
unless SILENT
|
150
|
-
$stderr.print("\033[0K\rProcessed: #{counter_links} of #{total_links}, #{counter_errors} errors. ")
|
151
|
-
end
|
125
|
+
reference_link = input =~ /:([!\^~\s]*)$/
|
152
126
|
|
153
|
-
|
154
|
-
|
155
|
-
|
127
|
+
# if end of input contains ~, pull url from clipboard
|
128
|
+
if input =~ /~[:\^!\s]*$/
|
129
|
+
input.sub!(/[:!\^\s~]*$/, "")
|
130
|
+
clipboard = `__CF_USER_TEXT_ENCODING=$UID:0x8000100:0x8000100 pbpaste`.strip
|
131
|
+
if SL::URL.url?(clipboard)
|
132
|
+
type = reference_link ? :ref_title : :inline
|
133
|
+
print SL.make_link(type, input.strip, clipboard)
|
134
|
+
else
|
135
|
+
print SL.originput
|
136
|
+
end
|
137
|
+
Process.exit
|
138
|
+
end
|
156
139
|
|
157
|
-
|
158
|
-
link_info.gsub!(/"(.*?)"/) do
|
159
|
-
m = Regexp.last_match
|
160
|
-
@link_text = m[1] if @link_text == ""
|
161
|
-
m[0]
|
162
|
-
end
|
163
|
-
end
|
140
|
+
input.sub!(/[:!\^\s~]*$/, "")
|
164
141
|
|
165
|
-
|
166
|
-
|
167
|
-
|
142
|
+
## Maybe if input is just a URL, convert it to a link
|
143
|
+
## using hostname as text without doing search
|
144
|
+
if SL::URL.only_url?(input.strip)
|
145
|
+
type = reference_link ? :ref_title : :inline
|
146
|
+
@url, title = SL::URL.url_to_link(input.strip, type)
|
147
|
+
print SL.make_link(type, title, @url, title: false, force_title: false)
|
148
|
+
Process.exit
|
149
|
+
end
|
168
150
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
151
|
+
# check for additional search terms in parenthesis
|
152
|
+
additional_terms = ""
|
153
|
+
if input =~ /\((.*?)\)/
|
154
|
+
additional_terms = " #{Regexp.last_match(1).strip}"
|
155
|
+
input.sub!(/\(.*?\)/, "")
|
156
|
+
end
|
173
157
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
158
|
+
# Maybe detect "search + addition terms" and remove additional terms from link text?
|
159
|
+
# if input =~ /\+(.+?)$/
|
160
|
+
# additional_terms = "#{additional_terms} #{Regexp.last_match(1).strip}"
|
161
|
+
# input.sub!(/\+.*?$/, '').strip!
|
162
|
+
# end
|
179
163
|
|
180
|
-
|
181
|
-
search_type = Regexp.last_match(1).extract_shortener
|
182
|
-
unless SL::Searches.valid_search?(search_type) || search_type =~ /^(\S+\.)+\S+$/
|
183
|
-
SL.add_error("Invalid search#{SL::Searches.did_you_mean(search_type)}", match)
|
184
|
-
invalid_search = true
|
185
|
-
end
|
186
|
-
end
|
164
|
+
@link_text = false
|
187
165
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
create_footnote(m)
|
193
|
-
# Handle [](URL) and [%](URL), filling in title
|
194
|
-
elsif (@link_text == "" || @link_text == "%") && SL::URL.url?(link_info)
|
195
|
-
add_title(link_info)
|
196
|
-
elsif (@link_text == "" && link_info == "") || SL::URL.url?(link_info)
|
197
|
-
SL.add_error("Invalid search", match) unless SL::URL.url?(link_info)
|
198
|
-
match
|
199
|
-
else
|
200
|
-
link_info = @link_text if !@link_text.empty? && link_info == ""
|
166
|
+
if input =~ /"(.*?)"/
|
167
|
+
@link_text = Regexp.last_match(1)
|
168
|
+
input.gsub!(/"(.*?)"/, '\1')
|
169
|
+
end
|
201
170
|
|
202
|
-
|
203
|
-
|
204
|
-
link_only = false
|
205
|
-
SL.clipboard = false
|
206
|
-
SL.titleize = SL.config["empty_uses_page_title"]
|
171
|
+
# remove quotes from terms, just in case
|
172
|
+
# input.sub!(/^(!\S+)?\s*(["'])(.*?)\2([\!\^]+)?$/, "\\1 \\3\\4")
|
207
173
|
|
208
|
-
|
209
|
-
|
174
|
+
case input
|
175
|
+
when /^!(\S+)\s+(.*)$/
|
176
|
+
type = Regexp.last_match(1).extract_shortener
|
177
|
+
link_info = Regexp.last_match(2).strip
|
210
178
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
m[1]
|
215
|
-
end
|
179
|
+
@link_text ||= link_info
|
180
|
+
terms = link_info + additional_terms
|
181
|
+
terms.strip!
|
216
182
|
|
217
|
-
|
183
|
+
if SL::Searches.valid_search?(type) || type =~ /^(\S+\.)+\S+$/
|
184
|
+
if type && terms && !terms.empty?
|
185
|
+
# Iterate through custom searches for a match, perform search if matched
|
186
|
+
type, terms = custom_search(type, terms)
|
187
|
+
end
|
218
188
|
|
219
|
-
|
220
|
-
|
189
|
+
# if contains TLD, use site-specific search
|
190
|
+
if type =~ /^(\S+\.)+\S+$/
|
191
|
+
terms = "site:#{type} #{terms}"
|
192
|
+
type = SL::GoogleSearch.api_key? ? "gg" : "g"
|
193
|
+
end
|
194
|
+
@search_count ||= 0
|
195
|
+
@search_count += 1
|
221
196
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
197
|
+
SL.add_query(query) if query
|
198
|
+
@url, title, @link_text = do_search(type, terms, @link_text, @search_count)
|
199
|
+
else
|
200
|
+
SL.add_error("Invalid search#{SL::Searches.did_you_mean(type)}", input)
|
201
|
+
SL.error_count
|
202
|
+
end
|
203
|
+
# Social handle expansion
|
204
|
+
when /^([tfilm])?@(\S+)\s*$/
|
205
|
+
type = Regexp.last_match(1)
|
206
|
+
type ||= if Regexp.last_match(2) =~ /[a-z0-9_]@[a-z0-9_.]+/i
|
207
|
+
"m"
|
208
|
+
else
|
209
|
+
"t"
|
210
|
+
end
|
211
|
+
@link_text = input.sub(/^[tfilm]/, "")
|
212
|
+
SL.add_query(query) if query
|
213
|
+
@url, title = SL::SocialSearch.social_handle(type, @link_text)
|
214
|
+
@link_text = title
|
215
|
+
else
|
216
|
+
SL.add_query(query) if query
|
217
|
+
@link_text ||= input
|
218
|
+
@url, title, @link_text = SL.ddg(input, @link_text)
|
219
|
+
end
|
227
220
|
|
228
|
-
|
221
|
+
if @url
|
222
|
+
res = confirmed?(@url)
|
223
|
+
if res
|
224
|
+
if res.is_a?(String) && SL::URL.url?(res)
|
225
|
+
@url = res
|
226
|
+
title = SL::URL.title(@url) if SL.titleize && title == ""
|
227
|
+
end
|
229
228
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
229
|
+
if type =~ /sp(ell)?/
|
230
|
+
SL.add_output(@url)
|
231
|
+
elsif link_only
|
232
|
+
SL.add_output(@url)
|
233
|
+
elsif @url == "embed"
|
234
|
+
SL.add_output(title)
|
235
|
+
else
|
236
|
+
type = reference_link ? :ref_title : :inline
|
234
237
|
|
235
|
-
|
236
|
-
|
238
|
+
SL.add_output SL.make_link(type, @link_text, @url, title: title, force_title: false)
|
239
|
+
SL.print_errors
|
240
|
+
end
|
241
|
+
else
|
242
|
+
SL.add_error("Canceled", "User canceled result #{@url}")
|
243
|
+
SL.add_output SL.originput.chomp
|
244
|
+
SL.print_errors
|
245
|
+
end
|
246
|
+
else
|
247
|
+
SL.add_error("No results", title)
|
248
|
+
SL.add_output SL.originput.chomp
|
249
|
+
SL.print_errors
|
250
|
+
end
|
237
251
|
|
238
|
-
|
239
|
-
link_only = true if search_terms =~ /!!\^?$/
|
252
|
+
return unless SL.clipboard
|
240
253
|
|
241
|
-
|
254
|
+
if SL.output == SL.originput
|
255
|
+
warn "No results found"
|
256
|
+
else
|
257
|
+
`echo #{Shellwords.escape(SL.output.join(""))}|tr -d "\n"|pbcopy`
|
258
|
+
warn "Results in clipboard"
|
259
|
+
end
|
260
|
+
end
|
242
261
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
end
|
247
|
-
elsif link_info =~ /^!/
|
248
|
-
search_word = link_info.match(/^!(\S+)/)
|
249
|
-
st = search_word[1].extract_shortener
|
250
|
-
if search_word && SL::Searches.valid_search?(st)
|
251
|
-
search_type = st unless search_word.nil?
|
252
|
-
search_terms = @link_text
|
253
|
-
elsif search_word && st =~ /^(\S+\.)+\S+$/
|
254
|
-
search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
|
255
|
-
search_terms = "site:#{search_word[1]} #{@link_text}"
|
256
|
-
else
|
257
|
-
SL.add_error("Invalid search#{SL::Searches.did_you_mean(st)}", match)
|
258
|
-
search_type = false
|
259
|
-
search_terms = false
|
260
|
-
end
|
261
|
-
elsif @link_text && !@link_text.empty? && (!link_info || link_info.empty?)
|
262
|
-
search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
|
263
|
-
search_terms = @link_text
|
264
|
-
elsif link_info && !link_info.empty?
|
265
|
-
search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
|
266
|
-
search_terms = link_info
|
267
|
-
else
|
268
|
-
SL.add_error("Invalid search", match)
|
269
|
-
search_type = false
|
270
|
-
search_terms = false
|
271
|
-
end
|
262
|
+
def parse_brackets(input)
|
263
|
+
lines = input.split("\n")
|
264
|
+
out = []
|
272
265
|
|
273
|
-
|
274
|
-
|
275
|
-
|
266
|
+
total_links = 0
|
267
|
+
in_code_block = false
|
268
|
+
in_list = false
|
269
|
+
last_indent = 0
|
270
|
+
line_difference = 0
|
271
|
+
counter_links = 0
|
272
|
+
lines.each_with_index do |line, num|
|
273
|
+
SL.line_num = num - line_difference
|
274
|
+
@cursor_difference = 0
|
276
275
|
|
277
|
-
|
276
|
+
if line =~ /^\s*[~`]{3,}/
|
277
|
+
if in_code_block
|
278
|
+
in_code_block = false
|
279
|
+
out.push(line)
|
280
|
+
next
|
281
|
+
else
|
282
|
+
in_code_block = true
|
283
|
+
end
|
284
|
+
elsif in_code_block
|
285
|
+
out.push(line)
|
286
|
+
next
|
287
|
+
elsif line.strip.empty?
|
288
|
+
out.push(line)
|
289
|
+
next
|
290
|
+
elsif line =~ /^\s*([-+*]|\d+\.)\s/
|
291
|
+
in_list = true
|
292
|
+
last_indent = line.indent_level
|
293
|
+
elsif in_list && line.indent_level > last_indent + 2
|
294
|
+
out.push(line)
|
295
|
+
next
|
296
|
+
elsif in_list && line.indent_level < last_indent && line !~ /^\s*([-+*]|\d+\.)\s/
|
297
|
+
in_list = false
|
298
|
+
elsif in_list && line.indent_level == last_indent + 1
|
299
|
+
# noop
|
300
|
+
else
|
301
|
+
in_list = false
|
302
|
+
# ignore links in code blocks
|
303
|
+
if line =~ /^(( {4,}|\t+)[^*+-])/
|
304
|
+
last_indent = line.indent_level
|
305
|
+
out.push(line)
|
306
|
+
next
|
307
|
+
end
|
308
|
+
last_indent = line.indent_level
|
309
|
+
end
|
278
310
|
|
279
|
-
|
280
|
-
# warn "Searching #{search_type} for #{search_terms}"
|
311
|
+
total_links += line.count_links
|
281
312
|
|
282
|
-
|
283
|
-
@url, title, @link_text = do_search(search_type, search_terms, @link_text, @search_count)
|
313
|
+
@delete_line = false
|
284
314
|
|
285
|
-
|
286
|
-
if title
|
287
|
-
@link_text = title
|
288
|
-
else
|
289
|
-
add_title(@url)
|
290
|
-
end
|
291
|
-
end
|
315
|
+
@search_count = 0
|
292
316
|
|
293
|
-
|
294
|
-
|
295
|
-
if !res
|
296
|
-
return match
|
297
|
-
else
|
298
|
-
@url = res if res.is_a?(String) && SL::URL.url?(res)
|
299
|
-
end
|
317
|
+
line.gsub!(/\[(.*?)\]\((.*?)\)/) do |match|
|
318
|
+
this_match = Regexp.last_match
|
300
319
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
if link_only || search_type =~ /sp(ell)?/ || @url == "embed"
|
307
|
-
@url = title if @url == "embed"
|
308
|
-
@cursor_difference += SL.match_length - @url.length
|
309
|
-
SL.match_length = @url.length
|
310
|
-
SL.add_report("#{@match_string} => #{@url}")
|
311
|
-
@url
|
312
|
-
elsif @ref_title
|
313
|
-
unless @links.key? @url
|
314
|
-
@links[@url] = @link_text
|
315
|
-
SL.add_footer SL.make_link(:ref_title, @link_text, @url, title: title, force_title: force_title)
|
316
|
-
end
|
317
|
-
@delete_line = true
|
318
|
-
elsif SL.config["inline"]
|
319
|
-
res = SL.make_link(:inline, @link_text, @url, title: title, force_title: force_title)
|
320
|
-
@cursor_difference += SL.match_length - res.length
|
321
|
-
SL.match_length = res.length
|
322
|
-
SL.add_report("#{@match_string} => #{@url}")
|
323
|
-
res
|
324
|
-
else
|
325
|
-
unless @links.key? @url
|
326
|
-
@highest_marker += 1
|
327
|
-
@links[@url] = format("%<pre>s%<m>04d", pre: @prefix, m: @highest_marker)
|
328
|
-
SL.add_footer SL.make_link(:ref_title, @links[@url], @url, title: title, force_title: force_title)
|
329
|
-
end
|
330
|
-
|
331
|
-
type = SL.config["inline"] ? :inline : :ref_link
|
332
|
-
res = SL.make_link(type, @link_text, @links[@url], title: false, force_title: force_title)
|
333
|
-
@cursor_difference += SL.match_length - res.length
|
334
|
-
SL.match_length = res.length
|
335
|
-
SL.add_report("#{@match_string} => #{@url}")
|
336
|
-
res
|
337
|
-
end
|
338
|
-
else
|
339
|
-
SL.add_error("No results", "#{search_terms} (#{@match_string})")
|
340
|
-
counter_errors += 1
|
341
|
-
match
|
342
|
-
end
|
343
|
-
else
|
344
|
-
SL.add_error("Invalid search", match)
|
345
|
-
counter_errors += 1
|
346
|
-
match
|
347
|
-
end
|
348
|
-
end
|
349
|
-
end
|
350
|
-
line_difference += 1 if @delete_line
|
351
|
-
out.push(line) unless @delete_line
|
352
|
-
@delete_line = false
|
353
|
-
end
|
354
|
-
warn "\n" unless SILENT
|
320
|
+
SL.match_column = this_match.begin(0) - @cursor_difference
|
321
|
+
@match_string = this_match.to_s
|
322
|
+
SL.match_length = @match_string.length
|
323
|
+
match_before = this_match.pre_match
|
355
324
|
|
356
|
-
|
325
|
+
invalid_search = false
|
326
|
+
@ref_title = false
|
357
327
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
elsif SL.footer.empty?
|
362
|
-
SL.add_output input
|
363
|
-
else
|
364
|
-
last_line = input.strip.split(/\n/)[-1]
|
365
|
-
case last_line
|
366
|
-
when /^\[.*?\]: http/
|
367
|
-
SL.add_output "#{input.rstrip}\n"
|
368
|
-
when /^\[\^.*?\]: /
|
369
|
-
SL.add_output input.rstrip
|
370
|
-
else
|
371
|
-
SL.add_output "#{input}\n\n"
|
328
|
+
if match_before.scan(/(^|[^\\])`/).length.odd?
|
329
|
+
SL.add_report("Match '#{@match_string}' within an inline code block")
|
330
|
+
invalid_search = true
|
372
331
|
end
|
373
|
-
|
374
|
-
|
332
|
+
counter_links += 1
|
333
|
+
$stderr.print("\033[0K\rProcessed: #{counter_links} of #{total_links}, #{SL.error_count} errors. ") unless SILENT
|
375
334
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
SL.print_errors
|
380
|
-
else # Assume single line input
|
381
|
-
link_only = false
|
382
|
-
SL.clipboard = false
|
335
|
+
@link_text = this_match[1] || ""
|
336
|
+
link_info = parse_arguments(this_match[2].strip).strip || ""
|
337
|
+
query, link_info = link_info.extract_query({})
|
383
338
|
|
384
|
-
|
385
|
-
|
386
|
-
|
339
|
+
if @link_text.strip == "" && link_info =~ /".*?"/
|
340
|
+
link_info.gsub!(/"(.*?)"/) do
|
341
|
+
m = Regexp.last_match
|
342
|
+
@link_text = m[1] if @link_text == ""
|
343
|
+
m[0]
|
344
|
+
end
|
345
|
+
end
|
387
346
|
|
388
|
-
|
389
|
-
|
347
|
+
link_info.gsub!(/<(.*?)>/) do
|
348
|
+
%(%22#{Regexp.last_match(1)}%22)
|
349
|
+
end
|
390
350
|
|
391
|
-
|
392
|
-
|
351
|
+
if link_info.strip =~ /:$/ && line.strip == match
|
352
|
+
@ref_title = true
|
353
|
+
link_info.sub!(/\s*:\s*$/, "")
|
354
|
+
end
|
393
355
|
|
394
|
-
|
356
|
+
if @link_text.empty? && link_info.sub(/^[!\^]\S+/, "").strip.empty?
|
357
|
+
SL.add_error("No input", match)
|
358
|
+
invalid_search = true
|
359
|
+
end
|
395
360
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
print SL.make_link(type, input.strip, clipboard)
|
403
|
-
else
|
404
|
-
print SL.originput
|
361
|
+
if link_info =~ /^!(\S+)/
|
362
|
+
search_type = Regexp.last_match(1).extract_shortener
|
363
|
+
unless SL::Searches.valid_search?(search_type) || search_type =~ /^(\S+\.)+\S+$/
|
364
|
+
SL.add_error("Invalid search#{SL::Searches.did_you_mean(search_type)}", match)
|
365
|
+
invalid_search = true
|
366
|
+
end
|
405
367
|
end
|
406
|
-
Process.exit
|
407
|
-
end
|
408
368
|
|
409
|
-
|
369
|
+
if invalid_search
|
370
|
+
match
|
371
|
+
elsif link_info =~ /^\^(.+)/
|
372
|
+
m = Regexp.last_match
|
373
|
+
create_footnote(m)
|
374
|
+
# Handle [](URL) and [%](URL), filling in title
|
375
|
+
elsif (@link_text == "" || @link_text == "%") && SL::URL.url?(link_info)
|
376
|
+
add_title(link_info)
|
377
|
+
elsif (@link_text == "" && link_info == "") || SL::URL.url?(link_info)
|
378
|
+
SL.add_error("Invalid search", match) unless SL::URL.url?(link_info)
|
379
|
+
match
|
380
|
+
else
|
381
|
+
link_info = @link_text if !@link_text.empty? && link_info == ""
|
410
382
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
print SL.make_link(type, title, @url, title: false, force_title: false)
|
417
|
-
Process.exit
|
418
|
-
end
|
383
|
+
search_type = ""
|
384
|
+
search_terms = ""
|
385
|
+
link_only = false
|
386
|
+
SL.clipboard = false
|
387
|
+
SL.titleize = SL.config["empty_uses_page_title"]
|
419
388
|
|
420
|
-
|
421
|
-
|
422
|
-
if input =~ /\((.*?)\)/
|
423
|
-
additional_terms = " #{Regexp.last_match(1).strip}"
|
424
|
-
input.sub!(/\(.*?\)/, "")
|
425
|
-
end
|
389
|
+
if link_info =~ /^(?:[!\^](\S+))\s*(.*)$/
|
390
|
+
m = Regexp.last_match
|
426
391
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
392
|
+
search_type = if m[1].nil?
|
393
|
+
SL::GoogleSearch.api_key? ? "gg" : "g"
|
394
|
+
else
|
395
|
+
m[1]
|
396
|
+
end
|
432
397
|
|
433
|
-
|
398
|
+
search_type.extract_shortener!
|
434
399
|
|
435
|
-
|
436
|
-
|
437
|
-
input.gsub!(/"(.*?)"/, '\1')
|
438
|
-
end
|
400
|
+
search_terms = m[2].gsub(/(^["']|["']$)/, "")
|
401
|
+
search_terms.strip!
|
439
402
|
|
440
|
-
|
441
|
-
|
403
|
+
# if the link text is just '%' replace with title regardless of config settings
|
404
|
+
if @link_text == "%" && search_terms && !search_terms.empty?
|
405
|
+
SL.titleize = true
|
406
|
+
@link_text = ""
|
407
|
+
end
|
442
408
|
|
443
|
-
|
444
|
-
when /^!(\S+)\s+(.*)$/
|
445
|
-
type = Regexp.last_match(1).extract_shortener
|
446
|
-
link_info = Regexp.last_match(2).strip
|
409
|
+
search_terms = @link_text if search_terms == ""
|
447
410
|
|
448
|
-
|
449
|
-
|
450
|
-
terms.strip!
|
411
|
+
# if the input starts with a +, append it to the link text as the search terms
|
412
|
+
search_terms = "#{@link_text} #{search_terms.strip.sub(/^\+\s*/, '')}" if search_terms.strip =~ /^\+[^+]/
|
451
413
|
|
452
|
-
|
453
|
-
|
454
|
-
# Iterate through custom searches for a match, perform search if matched
|
455
|
-
type, terms = custom_search(type, terms)
|
456
|
-
end
|
414
|
+
# if the end of input contain "^", copy to clipboard instead of STDOUT
|
415
|
+
SL.clipboard = true if search_terms =~ /(!!)?\^(!!)?$/
|
457
416
|
|
458
|
-
|
459
|
-
|
460
|
-
terms = "site:#{type} #{terms}"
|
461
|
-
type = SL::GoogleSearch.api_key? ? "gg" : "g"
|
462
|
-
end
|
463
|
-
@search_count ||= 0
|
464
|
-
@search_count += 1
|
417
|
+
# if the end of input contains "!!", only print the url
|
418
|
+
link_only = true if search_terms =~ /!!\^?$/
|
465
419
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
420
|
+
search_terms = search_terms.sub(/(!!)?\^?(!!)?$/, "")
|
421
|
+
|
422
|
+
if search_type =~ /^(\S+\.)+\S+$/
|
423
|
+
search_type = "g"
|
424
|
+
search_terms = "site:#{m[1]} #{search_terms}"
|
425
|
+
end
|
426
|
+
elsif link_info =~ /^!/
|
427
|
+
search_word = link_info.match(/^!(\S+)/)
|
428
|
+
st = search_word[1].extract_shortener
|
429
|
+
if search_word && SL::Searches.valid_search?(st)
|
430
|
+
search_type = st unless search_word.nil?
|
431
|
+
search_terms = @link_text
|
432
|
+
elsif search_word && st =~ /^(\S+\.)+\S+$/
|
433
|
+
search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
|
434
|
+
search_terms = "site:#{search_word[1]} #{@link_text}"
|
435
|
+
else
|
436
|
+
SL.add_error("Invalid search#{SL::Searches.did_you_mean(st)}", match)
|
437
|
+
search_type = false
|
438
|
+
search_terms = false
|
439
|
+
end
|
440
|
+
elsif @link_text && !@link_text.empty? && (!link_info || link_info.empty?)
|
441
|
+
search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
|
442
|
+
search_terms = @link_text
|
443
|
+
elsif link_info && !link_info.empty?
|
444
|
+
search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
|
445
|
+
search_terms = link_info
|
477
446
|
else
|
478
|
-
"
|
447
|
+
SL.add_error("Invalid search", match)
|
448
|
+
search_type = false
|
449
|
+
search_terms = false
|
479
450
|
end
|
480
|
-
@link_text = input.sub(/^[tfilm]/, "")
|
481
|
-
SL.add_query(query) if query
|
482
|
-
@url, title = SL::SocialSearch.social_handle(type, @link_text)
|
483
|
-
@link_text = title
|
484
|
-
else
|
485
|
-
SL.add_query(query) if query
|
486
|
-
@link_text ||= input
|
487
|
-
@url, title, @link_text = SL.ddg(input, @link_text)
|
488
|
-
end
|
489
451
|
|
490
|
-
|
491
|
-
res = confirmed?(@url)
|
492
|
-
if res
|
493
|
-
if res.is_a?(String) && SL::URL.url?(res)
|
494
|
-
@url = res
|
495
|
-
title = SL::URL.title(@url) unless title == ""
|
496
|
-
end
|
452
|
+
search_type, search_terms = custom_search(search_type, search_terms) if search_type && !search_terms.empty?
|
497
453
|
|
498
|
-
if
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
454
|
+
SL.add_query(query) if query
|
455
|
+
|
456
|
+
if (search_type && search_terms) || @url
|
457
|
+
# warn "Searching #{search_type} for #{search_terms}"
|
458
|
+
|
459
|
+
@search_count += 1
|
460
|
+
@url, title, @link_text = do_search(search_type, search_terms, @link_text, @search_count)
|
461
|
+
|
462
|
+
if (@link_text == "" || @link_text == "%") && @url
|
463
|
+
if title
|
464
|
+
@link_text = title
|
465
|
+
else
|
466
|
+
add_title(@url)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
if @url
|
471
|
+
res = confirmed?(@url)
|
472
|
+
return match unless res
|
473
|
+
|
474
|
+
@url = res if res.is_a?(String) && SL::URL.url?(res)
|
475
|
+
|
476
|
+
title = SL::URL.title(@url) if SL.titleize && (title.nil? || title.empty?)
|
477
|
+
|
478
|
+
@link_text = title if @link_text == "" && title
|
479
|
+
force_title = search_type =~ /def/ ? true : false
|
480
|
+
|
481
|
+
if link_only || search_type =~ /sp(ell)?/ || @url == "embed"
|
482
|
+
@url = title if @url == "embed"
|
483
|
+
@cursor_difference += SL.match_length - @url.length
|
484
|
+
SL.match_length = @url.length
|
485
|
+
SL.add_report("#{@match_string} => #{@url}")
|
486
|
+
@url
|
487
|
+
elsif @ref_title
|
488
|
+
unless @links.key? @url
|
489
|
+
@links[@url] = @link_text
|
490
|
+
SL.add_footer SL.make_link(:ref_title, @link_text, @url, title: title, force_title: force_title)
|
491
|
+
end
|
492
|
+
@delete_line = true
|
493
|
+
elsif SL.config["inline"]
|
494
|
+
res = SL.make_link(:inline, @link_text, @url, title: title, force_title: force_title)
|
495
|
+
@cursor_difference += SL.match_length - res.length
|
496
|
+
SL.match_length = res.length
|
497
|
+
SL.add_report("#{@match_string} => #{@url}")
|
498
|
+
res
|
499
|
+
else
|
500
|
+
unless @links.key? @url
|
501
|
+
@highest_marker += 1
|
502
|
+
@links[@url] = format("%<pre>s%<m>04d", pre: @prefix, m: @highest_marker)
|
503
|
+
SL.add_footer SL.make_link(:ref_title, @links[@url], @url, title: title, force_title: force_title)
|
504
|
+
end
|
506
505
|
|
507
|
-
|
508
|
-
|
506
|
+
type = SL.config["inline"] ? :inline : :ref_link
|
507
|
+
res = SL.make_link(type, @link_text, @links[@url], title: false, force_title: force_title)
|
508
|
+
@cursor_difference += SL.match_length - res.length
|
509
|
+
SL.match_length = res.length
|
510
|
+
SL.add_report("#{@match_string} => #{@url}")
|
511
|
+
res
|
512
|
+
end
|
513
|
+
else
|
514
|
+
SL.add_error("No results", "#{search_terms} (#{@match_string})")
|
515
|
+
match
|
516
|
+
end
|
517
|
+
else
|
518
|
+
SL.add_error("Invalid search", match)
|
519
|
+
match
|
509
520
|
end
|
510
|
-
else
|
511
|
-
SL.add_error("Canceled", "User canceled result #{@url}")
|
512
|
-
SL.add_output SL.originput.chomp
|
513
|
-
SL.print_errors
|
514
521
|
end
|
515
|
-
else
|
516
|
-
SL.add_error("No results", title)
|
517
|
-
SL.add_output SL.originput.chomp
|
518
|
-
SL.print_errors
|
519
522
|
end
|
523
|
+
line_difference += 1 if @delete_line
|
524
|
+
out.push(line) unless @delete_line
|
525
|
+
@delete_line = false
|
526
|
+
end
|
527
|
+
warn "\n" unless SILENT
|
520
528
|
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
529
|
+
input = out.delete_if { |l| l.strip =~ /^<!--DELETE-->$/ }.join("\n")
|
530
|
+
|
531
|
+
if SL.config["inline"]
|
532
|
+
SL.add_output "#{input}\n"
|
533
|
+
SL.add_output "\n#{SL.print_footer}" unless SL.footer.empty?
|
534
|
+
elsif SL.footer.empty?
|
535
|
+
SL.add_output input
|
536
|
+
else
|
537
|
+
last_line = input.strip.split("\n")[-1]
|
538
|
+
case last_line
|
539
|
+
when /^\[.*?\]: http/
|
540
|
+
SL.add_output "#{input.rstrip}\n"
|
541
|
+
when /^\[\^.*?\]: /
|
542
|
+
SL.add_output input.rstrip
|
543
|
+
else
|
544
|
+
SL.add_output "#{input}\n\n"
|
528
545
|
end
|
546
|
+
SL.add_output "#{SL.print_footer}\n\n"
|
529
547
|
end
|
530
|
-
end
|
531
548
|
|
532
|
-
|
549
|
+
SL.line_num = nil
|
550
|
+
SL.add_report("Processed: #{total_links} links, #{SL.error_count} errors.")
|
551
|
+
SL.print_report
|
552
|
+
SL.print_errors
|
553
|
+
end
|
533
554
|
|
534
555
|
def add_title(link_info)
|
535
556
|
@url = link_info
|
@@ -582,7 +603,8 @@ module SL
|
|
582
603
|
|
583
604
|
input.parse_flags! unless skip_flags
|
584
605
|
|
585
|
-
options = %w[debug country_code inline prefix_random include_titles remove_seo validate_links complete_bare
|
606
|
+
options = %w[debug country_code inline prefix_random include_titles remove_seo validate_links complete_bare
|
607
|
+
confirm]
|
586
608
|
options.each do |o|
|
587
609
|
if input =~ /^ *#{o}:\s+(\S+)$/
|
588
610
|
val = Regexp.last_match(1).strip
|
@@ -648,10 +670,10 @@ module SL
|
|
648
670
|
note = mtch[1].strip
|
649
671
|
@footnote_counter += 1
|
650
672
|
ref = if !@link_text.empty? && @link_text.scan(/\s/).empty?
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
673
|
+
@link_text
|
674
|
+
else
|
675
|
+
format("%<p>sfn%<c>04d", p: @prefix, c: @footnote_counter)
|
676
|
+
end
|
655
677
|
SL.add_footer "[^#{ref}]: #{note}"
|
656
678
|
res = "[^#{ref}]"
|
657
679
|
@cursor_difference += (SL.match_length - res.length)
|
@@ -675,12 +697,16 @@ module SL
|
|
675
697
|
search_type = "r"
|
676
698
|
tokens = v.scan(/\$term\d+[ds]?/).sort.uniq
|
677
699
|
|
678
|
-
if
|
700
|
+
if tokens.empty?
|
701
|
+
search_terms = v.gsub(/\$term[ds]?/i) do |mtch|
|
702
|
+
search_terms.downcase! if mtch =~ /d$/i
|
703
|
+
search_terms.slugify! if mtch =~ /s$/i
|
704
|
+
search_terms.url_encode
|
705
|
+
end
|
706
|
+
else
|
679
707
|
highest_token = 0
|
680
708
|
tokens.each do |token|
|
681
|
-
if token =~ /(\d+)[ds]?$/ && Regexp.last_match(1).to_i > highest_token
|
682
|
-
highest_token = Regexp.last_match(1).to_i
|
683
|
-
end
|
709
|
+
highest_token = Regexp.last_match(1).to_i if token =~ /(\d+)[ds]?$/ && Regexp.last_match(1).to_i > highest_token
|
684
710
|
end
|
685
711
|
terms_p = search_terms.split(/ +/)
|
686
712
|
if terms_p.length > highest_token
|
@@ -706,12 +732,6 @@ module SL
|
|
706
732
|
v.gsub!(/#{Regexp.escape(t) + re_down}/, replacement.url_encode)
|
707
733
|
end
|
708
734
|
search_terms = v
|
709
|
-
else
|
710
|
-
search_terms = v.gsub(/\$term[ds]?/i) do |mtch|
|
711
|
-
search_terms.downcase! if mtch =~ /d$/i
|
712
|
-
search_terms.slugify! if mtch =~ /s$/i
|
713
|
-
search_terms.url_encode
|
714
|
-
end
|
715
735
|
end
|
716
736
|
else
|
717
737
|
search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
|