snibbets 2.0.39 → 2.0.40
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/CHANGELOG.md +9 -0
- data/README.md +179 -37
- data/lib/snibbets/string.rb +18 -2
- data/lib/snibbets/version.rb +1 -1
- data/lib/snibbets.rb +141 -136
- data/mise.toml +2 -0
- data/src/_README.md +176 -36
- metadata +4 -8
- data/Gemfile.lock +0 -125
- data/lib/snibbets/todo_spec.rb +0 -11
data/lib/snibbets.rb
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require_relative
|
15
|
-
require_relative
|
16
|
-
require_relative
|
17
|
-
require_relative
|
18
|
-
require_relative
|
19
|
-
require_relative
|
20
|
-
require_relative
|
21
|
-
require_relative
|
22
|
-
require_relative
|
23
|
-
require_relative
|
24
|
-
require_relative
|
3
|
+
require "cgi"
|
4
|
+
require "erb"
|
5
|
+
require "fileutils"
|
6
|
+
require "json"
|
7
|
+
require "open3"
|
8
|
+
require "optparse"
|
9
|
+
require "readline"
|
10
|
+
require "shellwords"
|
11
|
+
require "tty-reader"
|
12
|
+
require "tty-which"
|
13
|
+
require "yaml"
|
14
|
+
require_relative "snibbets/version"
|
15
|
+
require_relative "snibbets/colors"
|
16
|
+
require_relative "snibbets/config"
|
17
|
+
require_relative "snibbets/which"
|
18
|
+
require_relative "snibbets/string"
|
19
|
+
require_relative "snibbets/hash"
|
20
|
+
require_relative "snibbets/array"
|
21
|
+
require_relative "snibbets/menu"
|
22
|
+
require_relative "snibbets/os"
|
23
|
+
require_relative "snibbets/highlight"
|
24
|
+
require_relative "snibbets/lexers"
|
25
25
|
|
26
26
|
# Top level module
|
27
27
|
module Snibbets
|
@@ -47,78 +47,84 @@ module Snibbets
|
|
47
47
|
end
|
48
48
|
|
49
49
|
# Search the snippets directory for query using find and grep
|
50
|
-
def search(try: 0)
|
50
|
+
def search(try: 0, matches: [])
|
51
51
|
folder = File.expand_path(Snibbets.options[:source])
|
52
|
-
# start by doing a spotlight search
|
53
|
-
#
|
54
|
-
#
|
55
|
-
|
52
|
+
# start by doing a spotlight search with mdfind
|
53
|
+
# next try only search by filenames (find)
|
54
|
+
# next try search with grep (rg, ag, ack, grep)
|
55
|
+
# concatenate results from each search, removing duplicates and sorting
|
56
|
+
ext = Snibbets.options[:extension] || "md"
|
57
|
+
|
56
58
|
cmd = case try
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
59
|
+
when 1
|
60
|
+
%(find "#{folder}" -iregex '^#{Regexp.escape(folder)}/#{@query.rx}' -name '*.#{ext}')
|
61
|
+
when 2
|
62
|
+
rg = TTY::Which.which("rg")
|
63
|
+
ag = TTY::Which.which("ag")
|
64
|
+
ack = TTY::Which.which("ack")
|
65
|
+
grep = TTY::Which.which("grep")
|
66
|
+
if !rg.empty?
|
67
|
+
%(#{rg} -li --color=never --glob='*.#{ext}' '#{@query.rx}' "#{folder}")
|
68
|
+
elsif !ag.empty?
|
69
|
+
%(#{ag} -li --nocolor -G '.*.#{ext}' '#{@query.rx}' "#{folder}")
|
70
|
+
elsif !ack.empty?
|
71
|
+
%(#{ack} -li --nocolor --markdown '#{@query.rx}' "#{folder}")
|
72
|
+
elsif !grep.empty?
|
73
|
+
%(#{grep} -iEl '#{@query.rx}' "#{folder}"/**/*.#{ext})
|
74
|
+
else
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
else
|
78
|
+
mdfind = TTY::Which.which("mdfind")
|
79
|
+
if mdfind.nil? || mdfind.empty?
|
80
|
+
nil
|
81
|
+
else
|
82
|
+
name_only = Snibbets.options[:name_only] ? "-name " : ""
|
83
|
+
%(mdfind -onlyin #{folder} #{name_only}'#{@query} name:.#{ext}' 2>/dev/null)
|
84
|
+
end
|
85
|
+
end
|
84
86
|
|
85
87
|
if try == 2
|
86
88
|
if Snibbets.options[:name_only]
|
87
|
-
puts
|
89
|
+
puts "{br}No name matches found".x
|
88
90
|
Process.exit 1
|
89
91
|
elsif cmd.nil?
|
90
|
-
puts
|
92
|
+
puts "{br}No search method available on this system. Please install ripgrep, silver surfer, ack, or grep.".x
|
91
93
|
Process.exit 1
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
95
|
-
res = cmd.nil? ?
|
96
|
-
|
97
|
-
matches = []
|
97
|
+
res = cmd.nil? ? "" : `#{cmd}`.strip
|
98
98
|
|
99
99
|
unless res.empty?
|
100
100
|
lines = res.split(/\n/)
|
101
101
|
lines.each do |l|
|
102
102
|
matches << {
|
103
|
-
|
104
|
-
|
103
|
+
"title" => File.basename(l, ".*"),
|
104
|
+
"path" => l,
|
105
105
|
}
|
106
106
|
end
|
107
107
|
|
108
|
-
matches.sort_by! { |a| a[
|
108
|
+
matches.sort_by! { |a| a["title"] }.uniq!
|
109
|
+
|
110
|
+
# return matches unless matches.empty?
|
111
|
+
end
|
109
112
|
|
110
|
-
|
113
|
+
matches.delete_if do |m|
|
114
|
+
content = IO.read(m["path"])
|
115
|
+
!content.match_all_tags(@query)
|
111
116
|
end
|
112
117
|
|
118
|
+
# return after 3 cycles
|
113
119
|
return matches if try == 2
|
114
120
|
|
115
|
-
#
|
116
|
-
search(try: try + 1
|
121
|
+
# continue search, appends to current matches
|
122
|
+
search(try: try + 1, matches: matches)
|
117
123
|
end
|
118
124
|
|
119
125
|
def open_snippet_in_nvultra(filepath)
|
120
|
-
notebook = Snibbets.options[:source].gsub(/ /,
|
121
|
-
note = ERB::Util.url_encode(File.basename(filepath,
|
126
|
+
notebook = Snibbets.options[:source].gsub(/ /, "%20")
|
127
|
+
note = ERB::Util.url_encode(File.basename(filepath, ".md"))
|
122
128
|
url = "x-nvultra://open?notebook=#{notebook}¬e=#{note}"
|
123
129
|
`open '#{url}'`
|
124
130
|
end
|
@@ -126,7 +132,7 @@ module Snibbets
|
|
126
132
|
def open_snippet_in_editor(filepath)
|
127
133
|
editor = Snibbets.options[:editor] || Snibbets::Config.best_editor
|
128
134
|
|
129
|
-
os = RbConfig::CONFIG[
|
135
|
+
os = RbConfig::CONFIG["target_os"]
|
130
136
|
|
131
137
|
if editor.nil?
|
132
138
|
OS.open(filepath)
|
@@ -158,7 +164,7 @@ module Snibbets
|
|
158
164
|
def new_snippet_from_clipboard
|
159
165
|
return false unless $stdout.isatty
|
160
166
|
|
161
|
-
trap(
|
167
|
+
trap("SIGINT") do
|
162
168
|
Howzit.console.info "\nCancelled"
|
163
169
|
exit!
|
164
170
|
end
|
@@ -167,10 +173,10 @@ module Snibbets
|
|
167
173
|
reader = TTY::Reader.new
|
168
174
|
|
169
175
|
begin
|
170
|
-
input = reader.read_line(
|
176
|
+
input = reader.read_line("{by}What does this snippet do{bw}? ".x).strip
|
171
177
|
title = input unless input.empty?
|
172
178
|
|
173
|
-
input = reader.read_line(
|
179
|
+
input = reader.read_line("{by}What language(s) does it use ({xw}separate with spaces, full names or file extensions{by}){bw}? ".x).strip
|
174
180
|
langs = input.split(/ +/).map(&:strip) unless input.empty?
|
175
181
|
rescue TTY::Reader::InputInterrupt
|
176
182
|
puts "\nCancelled"
|
@@ -182,10 +188,10 @@ module Snibbets
|
|
182
188
|
|
183
189
|
exts = langs if exts.empty?
|
184
190
|
|
185
|
-
filename = "#{title}#{exts.map { |x| ".#{x}" }.join(
|
191
|
+
filename = "#{title}#{exts.map { |x| ".#{x}" }.join("")}.#{Snibbets.options[:extension]}"
|
186
192
|
filepath = File.join(File.expand_path(Snibbets.options[:source]), filename.escape_filename)
|
187
|
-
File.open(filepath,
|
188
|
-
f.puts "tags: #{tags.join(
|
193
|
+
File.open(filepath, "w") do |f|
|
194
|
+
f.puts "tags: #{tags.join(", ")}
|
189
195
|
|
190
196
|
```
|
191
197
|
#{pb}
|
@@ -201,20 +207,20 @@ module Snibbets
|
|
201
207
|
def new_snippet_with_editor(options)
|
202
208
|
return false unless $stdout.isatty
|
203
209
|
|
204
|
-
trap(
|
210
|
+
trap("SIGINT") do
|
205
211
|
Howzit.console.info "\nCancelled"
|
206
212
|
exit!
|
207
213
|
end
|
208
214
|
|
209
215
|
reader = TTY::Reader.new
|
210
216
|
if options[:filename]
|
211
|
-
title = options[:filename].sub(/(\.#{Snibbets.options[:extension]})$/,
|
217
|
+
title = options[:filename].sub(/(\.#{Snibbets.options[:extension]})$/, "")
|
212
218
|
extensions = options[:filename].match(/(\.\w+)+$/)
|
213
219
|
langs = extensions ? extensions[0].split(/\./).delete_if(&:empty?) : []
|
214
|
-
title.sub!(/(\.\w+)+$/,
|
220
|
+
title.sub!(/(\.\w+)+$/, "")
|
215
221
|
else
|
216
222
|
begin
|
217
|
-
input = reader.read_line(
|
223
|
+
input = reader.read_line("{by}What does this snippet do{bw}? ".x).strip
|
218
224
|
title = input unless input.empty?
|
219
225
|
rescue TTY::Reader::InputInterrupt
|
220
226
|
puts "\nCancelled"
|
@@ -225,7 +231,7 @@ module Snibbets
|
|
225
231
|
if langs.nil? || langs.empty?
|
226
232
|
begin
|
227
233
|
# printf 'What language(s) does it use (separate with spaces, full names or file extensions will work)? '
|
228
|
-
input = reader.read_line(
|
234
|
+
input = reader.read_line("{by}What language(s) does it use ({xw}separate with spaces, full names or file extensions{by}){bw}? ".x).strip
|
229
235
|
# input = $stdin.gets.chomp
|
230
236
|
langs = input.split(/ +/).map(&:strip) unless input.empty?
|
231
237
|
rescue TTY::Reader::InputInterrupt
|
@@ -239,11 +245,11 @@ module Snibbets
|
|
239
245
|
|
240
246
|
exts = langs if exts.empty?
|
241
247
|
|
242
|
-
filename = "#{title}#{exts.map { |x| ".#{x}" }.join(
|
248
|
+
filename = "#{title}#{exts.map { |x| ".#{x}" }.join("")}.#{Snibbets.options[:extension]}"
|
243
249
|
filepath = File.join(File.expand_path(Snibbets.options[:source]), filename.escape_filename)
|
244
250
|
|
245
|
-
output
|
246
|
-
tags: #{tags.join(
|
251
|
+
output = <<~EOOUTPUT
|
252
|
+
tags: #{tags.join(", ")}
|
247
253
|
|
248
254
|
> #{title}
|
249
255
|
EOOUTPUT
|
@@ -251,11 +257,11 @@ module Snibbets
|
|
251
257
|
if langs.count.positive?
|
252
258
|
tags.each do |lang|
|
253
259
|
comment = case lang
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
260
|
+
when /(c|cpp|objectivec|java|javascript|dart|php|golang|typescript|kotlin)/
|
261
|
+
"// Code"
|
262
|
+
else
|
263
|
+
"# Code"
|
264
|
+
end
|
259
265
|
|
260
266
|
output << <<~EOLANGS
|
261
267
|
|
@@ -271,7 +277,7 @@ module Snibbets
|
|
271
277
|
EOCODE
|
272
278
|
end
|
273
279
|
|
274
|
-
File.open(filepath,
|
280
|
+
File.open(filepath, "w") do |f|
|
275
281
|
f.puts output
|
276
282
|
end
|
277
283
|
|
@@ -290,14 +296,14 @@ module Snibbets
|
|
290
296
|
|
291
297
|
if results.empty?
|
292
298
|
out = {
|
293
|
-
|
299
|
+
"title" => "No matching snippets found",
|
294
300
|
}.to_json
|
295
301
|
puts out
|
296
302
|
Process.exit
|
297
303
|
end
|
298
304
|
|
299
305
|
results.each do |result|
|
300
|
-
input = IO.read(result[
|
306
|
+
input = IO.read(result["path"])
|
301
307
|
snippets = input.snippets
|
302
308
|
next if snippets.empty?
|
303
309
|
|
@@ -305,29 +311,29 @@ module Snibbets
|
|
305
311
|
|
306
312
|
if snippets.length == 1
|
307
313
|
output << {
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
314
|
+
"title" => result["title"],
|
315
|
+
"path" => result["path"],
|
316
|
+
"action" => "copyIt",
|
317
|
+
"actionArgument" => snippets[0]["code"],
|
318
|
+
"label" => "Copy",
|
313
319
|
}
|
314
320
|
next
|
315
321
|
end
|
316
322
|
|
317
323
|
snippets.each { |s|
|
318
324
|
children << {
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
325
|
+
"title" => s["title"],
|
326
|
+
"path" => result["path"],
|
327
|
+
"action" => "copyIt",
|
328
|
+
"actionArgument" => s["code"],
|
329
|
+
"label" => "Copy",
|
324
330
|
}
|
325
331
|
}
|
326
332
|
|
327
333
|
output << {
|
328
|
-
|
329
|
-
|
330
|
-
|
334
|
+
"title" => result["title"],
|
335
|
+
"path" => result["path"],
|
336
|
+
"children" => children,
|
331
337
|
}
|
332
338
|
end
|
333
339
|
|
@@ -340,14 +346,14 @@ module Snibbets
|
|
340
346
|
else
|
341
347
|
filepath = nil
|
342
348
|
if results.empty?
|
343
|
-
warn
|
349
|
+
warn "No results" if Snibbets.options[:interactive]
|
344
350
|
Process.exit 0
|
345
351
|
elsif results.length == 1 || !Snibbets.options[:interactive]
|
346
|
-
filepath = results[0][
|
352
|
+
filepath = results[0]["path"]
|
347
353
|
input = IO.read(filepath)
|
348
354
|
else
|
349
|
-
answer = Snibbets::Menu.menu(results, title:
|
350
|
-
filepath = answer[
|
355
|
+
answer = Snibbets::Menu.menu(results, title: "Select a file")
|
356
|
+
filepath = answer["path"]
|
351
357
|
input = IO.read(filepath)
|
352
358
|
end
|
353
359
|
|
@@ -364,21 +370,21 @@ module Snibbets
|
|
364
370
|
snippets = input.snippets
|
365
371
|
|
366
372
|
if snippets.empty?
|
367
|
-
warn
|
373
|
+
warn "No snippets found" if Snibbets.options[:interactive]
|
368
374
|
Process.exit 0
|
369
375
|
elsif snippets.length == 1 || !Snibbets.options[:interactive]
|
370
|
-
if Snibbets.options[:output] ==
|
376
|
+
if Snibbets.options[:output] == "json"
|
371
377
|
print(snippets.to_json, filepath)
|
372
378
|
else
|
373
379
|
snippets.each do |snip|
|
374
|
-
header = File.basename(filepath,
|
380
|
+
header = File.basename(filepath, ".md")
|
375
381
|
if $stdout.isatty
|
376
382
|
puts "{bw}#{header}{x}".x
|
377
|
-
puts "{dw}#{
|
378
|
-
puts
|
383
|
+
puts "{dw}#{"-" * header.length}{x}".x
|
384
|
+
puts ""
|
379
385
|
end
|
380
|
-
code = snip[
|
381
|
-
lang = snip[
|
386
|
+
code = snip["code"]
|
387
|
+
lang = snip["language"]
|
382
388
|
|
383
389
|
print(code, filepath, lang)
|
384
390
|
end
|
@@ -394,49 +400,48 @@ module Snibbets
|
|
394
400
|
end
|
395
401
|
|
396
402
|
def select_snippet(snippets, filepath)
|
397
|
-
snippets.push({
|
398
|
-
answer = Menu.menu(snippets.dup, filename: File.basename(filepath,
|
403
|
+
snippets.push({ "title" => "All snippets", "code" => "" })
|
404
|
+
answer = Menu.menu(snippets.dup, filename: File.basename(filepath, ".md"), title: "Select snippet", query: @query)
|
399
405
|
|
400
|
-
if answer[
|
401
|
-
snippets.delete_if { |s| s[
|
402
|
-
if Snibbets.options[:output] ==
|
406
|
+
if answer["title"] == "All snippets"
|
407
|
+
snippets.delete_if { |s| s["title"] == "All snippets" }
|
408
|
+
if Snibbets.options[:output] == "json"
|
403
409
|
print(snippets.to_json, filepath)
|
404
410
|
else
|
405
411
|
if $stdout.isatty
|
406
|
-
header = File.basename(filepath,
|
412
|
+
header = File.basename(filepath, ".md")
|
407
413
|
warn "{bw}#{header}{x}".x
|
408
|
-
warn "{dw}#{
|
409
|
-
warn
|
414
|
+
warn "{dw}#{"=" * header.length}{x}".x
|
415
|
+
warn ""
|
410
416
|
end
|
411
417
|
print_all(snippets, filepath)
|
412
418
|
end
|
413
|
-
elsif Snibbets.options[:output] ==
|
419
|
+
elsif Snibbets.options[:output] == "json"
|
414
420
|
print(answer.to_json, filepath)
|
415
421
|
else
|
416
422
|
if $stdout.isatty
|
417
|
-
header = "{bw}#{File.basename(filepath,
|
423
|
+
header = "{bw}#{File.basename(filepath, ".md")}: {c}#{answer["title"]}{x}".x
|
418
424
|
warn header
|
419
|
-
warn
|
420
|
-
warn
|
425
|
+
warn "-" * header.length
|
426
|
+
warn ""
|
421
427
|
end
|
422
|
-
code = answer[
|
423
|
-
lang = answer[
|
428
|
+
code = answer["code"]
|
429
|
+
lang = answer["language"]
|
424
430
|
print(code, filepath, lang)
|
425
431
|
end
|
426
432
|
end
|
427
433
|
|
428
434
|
def print_all(snippets, filepath)
|
429
|
-
if Snibbets.options[:output] ==
|
435
|
+
if Snibbets.options[:output] == "json"
|
430
436
|
print(snippets.to_json, filepath)
|
431
437
|
else
|
432
|
-
|
433
438
|
snippets.each do |snippet|
|
434
|
-
lang = snippet[
|
439
|
+
lang = snippet["language"]
|
435
440
|
|
436
|
-
puts "{dw}### {xbw}#{snippet[
|
437
|
-
puts
|
441
|
+
puts "{dw}### {xbw}#{snippet["title"]} {xdw}### {x}".x
|
442
|
+
puts ""
|
438
443
|
|
439
|
-
print(snippet[
|
444
|
+
print(snippet["code"], filepath, lang)
|
440
445
|
puts
|
441
446
|
end
|
442
447
|
end
|
@@ -445,9 +450,9 @@ module Snibbets
|
|
445
450
|
def print(output, filepath, syntax = nil)
|
446
451
|
if Snibbets.options[:copy]
|
447
452
|
OS.copy(Snibbets.options[:all_notes] ? output : output.clean_code)
|
448
|
-
warn
|
453
|
+
warn "Copied to clipboard"
|
449
454
|
end
|
450
|
-
if Snibbets.options[:highlight] && Snibbets.options[:output] ==
|
455
|
+
if Snibbets.options[:highlight] && Snibbets.options[:output] == "raw"
|
451
456
|
$stdout.puts(Highlight.highlight(output, filepath, syntax))
|
452
457
|
else
|
453
458
|
$stdout.puts(Snibbets.options[:all_notes] ? output : output.clean_code)
|
data/mise.toml
ADDED