snibbets 2.0.30 → 2.0.32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.devcontainer/Dockerfile +11 -0
- data/.devcontainer/devcontainer.json +17 -0
- data/.editorconfig +9 -0
- data/.irbrc +2 -0
- data/.rspec +4 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Snibbets.lbaction/Contents/Info.plist +49 -0
- data/Snibbets.lbaction/Contents/Scripts/default.js +52 -0
- data/Snibbets.lbaction/Contents/Scripts/snibbets.rb +420 -0
- data/lib/snibbets/array.rb +4 -0
- data/lib/snibbets/highlight.rb +17 -1
- data/lib/snibbets/string.rb +37 -9
- data/lib/snibbets/todo_spec.rb +11 -0
- data/lib/snibbets/version.rb +1 -1
- data/lib/snibbets.rb +6 -6
- data/scripts/fixreadme.rb +23 -0
- data/snibbets.gemspec +3 -3
- data/{README.md.orig → src/_README.md} +56 -35
- data/yard_templates/default/method_details/setup.rb +3 -0
- metadata +15 -6
- data/Gemfile.lock.orig +0 -107
- data/buildnotes.md +0 -47
- data/snibbets.taskpaper +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6701119f370f7f3a6190d811e5278799c973ed65b7f69a096b2675c91a2a124
|
4
|
+
data.tar.gz: 6954526979c677af6c5cf3fece76c0df0eae2f83ae2975c00e2884e99a5a2cda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e3cf0a812450aacd9dd69863bb4ba02880fb57049e396ab7d02eb31b024ed12aabe1f84dd4ace68b5ccc3d2c29e09c114776fde050b4bdc5708fcf01dfe5af9
|
7
|
+
data.tar.gz: 761105292b069c127ec2e32f0d39235883c4bd75d88b395d1a20b83b7fc6819aec0e9b5df67af14c7a2990196e5611aabf212afead13587ed2d62c2356489d34
|
@@ -0,0 +1,11 @@
|
|
1
|
+
ARG VARIANT="3"
|
2
|
+
|
3
|
+
FROM mcr.microsoft.com/vscode/devcontainers/ruby:${VARIANT}
|
4
|
+
|
5
|
+
USER vscode
|
6
|
+
WORKDIR /home/vscode
|
7
|
+
|
8
|
+
RUN mkdir -p .config/git \
|
9
|
+
&& echo ".vscode/*" >> .config/git/ignore \
|
10
|
+
&& echo "*.code-workspace" >> .config/git/ignore \
|
11
|
+
&& echo ".history/" >> .config/git/ignore
|
@@ -0,0 +1,17 @@
|
|
1
|
+
{
|
2
|
+
"name": "Ruby",
|
3
|
+
"build": {
|
4
|
+
"dockerfile": "Dockerfile",
|
5
|
+
"args": {
|
6
|
+
"VARIANT": "3"
|
7
|
+
}
|
8
|
+
},
|
9
|
+
"extensions": [
|
10
|
+
"rebornix.Ruby",
|
11
|
+
"ms-vsliveshare.vsliveshare",
|
12
|
+
"EditorConfig.EditorConfig",
|
13
|
+
"esbenp.prettier-vscode"
|
14
|
+
],
|
15
|
+
"postCreateCommand": "bundle install",
|
16
|
+
"remoteUser": "vscode"
|
17
|
+
}
|
data/.editorconfig
ADDED
data/.irbrc
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
### 2.0.32
|
2
|
+
|
3
|
+
2023-04-25 17:14
|
4
|
+
|
5
|
+
#### FIXED
|
6
|
+
|
7
|
+
- Don't highlight code sent to `--copy`
|
8
|
+
|
9
|
+
### 2.0.31
|
10
|
+
|
11
|
+
2023-04-20 10:20
|
12
|
+
|
13
|
+
#### IMPROVED
|
14
|
+
|
15
|
+
- Syntax highlight blocks individually, so multiple languages can exist within one snippet
|
16
|
+
- If outputting notes, wrap code in backticks to differentiate
|
17
|
+
|
18
|
+
#### FIXED
|
19
|
+
|
20
|
+
- Handle cases where snippet contains `\k<name>` and breaks regex replacement even with Regexp.escape
|
21
|
+
- Remove fences from single snippet when not syntax highlighting
|
22
|
+
|
1
23
|
### 2.0.30
|
2
24
|
|
3
25
|
2023-04-19 06:44
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -159,7 +159,7 @@ Snibbet's implementation of Skylighting has limited but better-looking themes, a
|
|
159
159
|
### Usage
|
160
160
|
|
161
161
|
```
|
162
|
-
Snibbets v2.0.
|
162
|
+
Snibbets v2.0.32
|
163
163
|
|
164
164
|
Usage: snibbets [options] query
|
165
165
|
-a, --all If a file contains multiple snippets, output all of them (no menu)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>CFBundleIdentifier</key>
|
6
|
+
<string>com.brettterpstra.LaunchBar.action.Snibbets</string>
|
7
|
+
<key>CFBundleName</key>
|
8
|
+
<string>Snibbets</string>
|
9
|
+
<key>LBAbbreviation</key>
|
10
|
+
<string>snib</string>
|
11
|
+
<key>LBDebugLogEnabled</key>
|
12
|
+
<true/>
|
13
|
+
<key>LBDescription</key>
|
14
|
+
<dict>
|
15
|
+
<key>LBAuthor</key>
|
16
|
+
<string>Brett Terpstra</string>
|
17
|
+
<key>LBEmail</key>
|
18
|
+
<string>me@brettterpstra.com</string>
|
19
|
+
<key>LBSummary</key>
|
20
|
+
<string>Search a folder of plain text code snippets and paste results</string>
|
21
|
+
<key>LBTwitter</key>
|
22
|
+
<string>@ttscoff</string>
|
23
|
+
<key>LBWebsiteURL</key>
|
24
|
+
<string></string>
|
25
|
+
</dict>
|
26
|
+
<key>LBScripts</key>
|
27
|
+
<dict>
|
28
|
+
<key>LBDefaultScript</key>
|
29
|
+
<dict>
|
30
|
+
<key>LBAcceptedArgumentTypes</key>
|
31
|
+
<array>
|
32
|
+
<string>string</string>
|
33
|
+
</array>
|
34
|
+
<key>LBKeepWindowActive</key>
|
35
|
+
<true/>
|
36
|
+
<key>LBResultType</key>
|
37
|
+
<string>unknown</string>
|
38
|
+
<key>LBReturnsResult</key>
|
39
|
+
<true/>
|
40
|
+
<key>LBScriptName</key>
|
41
|
+
<string>default.js</string>
|
42
|
+
</dict>
|
43
|
+
</dict>
|
44
|
+
<key>LBTextInputTitle</key>
|
45
|
+
<string>Search snippets</string>
|
46
|
+
<key>NSHumanReadableCopyright</key>
|
47
|
+
<string>Brett Terpstra 2019</string>
|
48
|
+
</dict>
|
49
|
+
</plist>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
// LaunchBar Action Script
|
2
|
+
|
3
|
+
function run() {
|
4
|
+
settingsItem = {
|
5
|
+
'title' : 'Choose Snippets Folder',
|
6
|
+
'action' : 'setFolder',
|
7
|
+
'label' : 'Choose',
|
8
|
+
'subtitle' : ''
|
9
|
+
}
|
10
|
+
if (Action.preferences.snippetsFolder) {
|
11
|
+
settingsItem.subtitle = Action.preferences.snippetsFolder;
|
12
|
+
}
|
13
|
+
return [settingsItem];
|
14
|
+
}
|
15
|
+
|
16
|
+
function runWithString(string) {
|
17
|
+
var folder = Action.preferences.snippetsFolder;
|
18
|
+
var result = LaunchBar.execute('/usr/bin/env', 'ruby' , 'snibbets.rb', '-o', 'launchbar', '-s', encodeURI(folder), encodeURI(string));
|
19
|
+
if (result)
|
20
|
+
return JSON.parse(result);
|
21
|
+
else
|
22
|
+
return {'title': 'No matches'}
|
23
|
+
}
|
24
|
+
|
25
|
+
function copyIt(item) {
|
26
|
+
LaunchBar.setClipboardString(item);
|
27
|
+
LaunchBar.openCommandURL('hide'); // for some reason LaunchBar.hide() doesn't execute, but this does. Sometimes.
|
28
|
+
LaunchBar.hide();
|
29
|
+
}
|
30
|
+
|
31
|
+
function pasteIt(item) {
|
32
|
+
LaunchBar.paste(item.code);
|
33
|
+
LaunchBar.openCommandURL('hide');
|
34
|
+
LaunchBar.hide();
|
35
|
+
}
|
36
|
+
|
37
|
+
function setFolder(item) {
|
38
|
+
LaunchBar.displayInLargeType({
|
39
|
+
title: 'Choosing folder'
|
40
|
+
});
|
41
|
+
var defaultFolder = LaunchBar.homeDirectory;
|
42
|
+
if (Action.preferences.snippetsFolder) {
|
43
|
+
defaultFolder = Action.preferences.snippetsFolder;
|
44
|
+
}
|
45
|
+
var k = LaunchBar.executeAppleScript(
|
46
|
+
'set _default to POSIX file "' + defaultFolder + '" as alias \n' +
|
47
|
+
'set _folder to choose folder with prompt "Select Snippets Folder" default location _default \n' +
|
48
|
+
' return POSIX path of _folder');
|
49
|
+
if (k && k.length > 0) {
|
50
|
+
Action.preferences.snippetsFolder = k.trim();
|
51
|
+
}
|
52
|
+
}
|
@@ -0,0 +1,420 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Snibbets 2.0.0
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'readline'
|
6
|
+
require 'json'
|
7
|
+
require 'cgi'
|
8
|
+
require 'shellwords'
|
9
|
+
|
10
|
+
$search_path = File.expand_path("~/Desktop/Code/Snippets")
|
11
|
+
|
12
|
+
class String
|
13
|
+
# Are there multiple snippets (indicated by ATX headers)
|
14
|
+
def multiple?
|
15
|
+
return self.scan(/^#+/).length > 1
|
16
|
+
end
|
17
|
+
|
18
|
+
# Is the snippet in this block fenced?
|
19
|
+
def fenced?
|
20
|
+
count = self.scan(/^```/).length
|
21
|
+
return count > 1 && count.even?
|
22
|
+
end
|
23
|
+
|
24
|
+
def rx
|
25
|
+
return ".*" + self.gsub(/\s+/,'.*') + ".*"
|
26
|
+
end
|
27
|
+
|
28
|
+
# remove outside comments, fences, and indentation
|
29
|
+
def clean_code
|
30
|
+
block = self
|
31
|
+
|
32
|
+
# if it's a fenced code block, just discard the fence and everything
|
33
|
+
# outside it
|
34
|
+
if block.fenced?
|
35
|
+
return block.gsub(/(?:^|.*?\n)(`{3,})(\w+)?(.*?)\n\1.*/m) {|m| $3.strip }
|
36
|
+
end
|
37
|
+
|
38
|
+
# assume it's indented code, discard non-indented lines and outdent
|
39
|
+
# the rest
|
40
|
+
indent = nil
|
41
|
+
inblock = false
|
42
|
+
code = []
|
43
|
+
block.split(/\n/).each {|line|
|
44
|
+
if line =~ /^\s*$/ && inblock
|
45
|
+
code.push(line)
|
46
|
+
elsif line =~ /^( {4,}|\t+)/
|
47
|
+
inblock = true
|
48
|
+
indent ||= Regexp.new("^#{$1}")
|
49
|
+
code.push(line.sub(indent,''))
|
50
|
+
else
|
51
|
+
inblock = false
|
52
|
+
end
|
53
|
+
}
|
54
|
+
code.join("\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns an array of snippets. Single snippets are returned without a
|
58
|
+
# title, multiple snippets get titles from header lines
|
59
|
+
def snippets
|
60
|
+
content = self.dup
|
61
|
+
# If there's only one snippet, just clean it and return
|
62
|
+
unless self.multiple?
|
63
|
+
return [{"title" => "", "code" => content.clean_code.strip}]
|
64
|
+
end
|
65
|
+
|
66
|
+
# Split content by ATX headers. Everything on the line after the #
|
67
|
+
# becomes the title, code is gleaned from text between that and the
|
68
|
+
# next ATX header (or end)
|
69
|
+
sections = []
|
70
|
+
parts = content.split(/^#+/)
|
71
|
+
parts.shift
|
72
|
+
|
73
|
+
parts.each do |p|
|
74
|
+
lines = p.split(/\n/)
|
75
|
+
title = lines.shift.strip.sub(/[.:]$/, '')
|
76
|
+
block = lines.join("\n")
|
77
|
+
code = block.clean_code
|
78
|
+
next unless code && !code.empty?
|
79
|
+
|
80
|
+
sections << {
|
81
|
+
'title' => title,
|
82
|
+
'code' => code.strip
|
83
|
+
}
|
84
|
+
end
|
85
|
+
return sections
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def gum_menu(executable, res, title)
|
90
|
+
options = res.map { |m| m['title'] }
|
91
|
+
puts title
|
92
|
+
selection = `echo #{Shellwords.escape(options.join("\n"))} | #{executable} choose --limit 1`.strip
|
93
|
+
Process.exit 1 if selection.empty?
|
94
|
+
|
95
|
+
res.select { |m| m['title'] =~ /#{selection}/ }[0]
|
96
|
+
end
|
97
|
+
|
98
|
+
def fzf_menu(executable, res, title)
|
99
|
+
options = res.map { |m| m['title'] }
|
100
|
+
args = [
|
101
|
+
"--height=#{options.count + 2}",
|
102
|
+
%(--prompt="#{title} > "),
|
103
|
+
'-1'
|
104
|
+
]
|
105
|
+
selection = `echo #{Shellwords.escape(options.join("\n"))} | #{executable} #{args.join(' ')}`.strip
|
106
|
+
Process.exit 1 if selection.empty?
|
107
|
+
|
108
|
+
res.select { |m| m['title'] =~ /#{selection}/ }[0]
|
109
|
+
end
|
110
|
+
|
111
|
+
def menu(res, title = 'Select one')
|
112
|
+
fzf = `which fzf`.strip
|
113
|
+
return fzf_menu(fzf, res, title) unless fzf.empty?
|
114
|
+
|
115
|
+
gum = `which gum`.strip
|
116
|
+
return gum_menu(gum, res, title) unless gum.empty?
|
117
|
+
|
118
|
+
console_menu(res, title)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Generate a numbered menu, items passed must have a title property
|
122
|
+
def console_menu(res, title)
|
123
|
+
stty_save = `stty -g`.chomp
|
124
|
+
|
125
|
+
trap('INT') do
|
126
|
+
system('stty', stty_save)
|
127
|
+
Process.exit 1
|
128
|
+
end
|
129
|
+
|
130
|
+
# Generate a numbered menu, items passed must have a title property('INT') { system('stty', stty_save); exit }
|
131
|
+
counter = 1
|
132
|
+
$stderr.puts
|
133
|
+
res.each do |m|
|
134
|
+
$stderr.printf("%<counter>2d) %<title>s\n", counter: counter, title: m['title'])
|
135
|
+
counter += 1
|
136
|
+
end
|
137
|
+
$stderr.puts
|
138
|
+
|
139
|
+
begin
|
140
|
+
$stderr.printf(title.sub(/:?$/, ': '), res.length)
|
141
|
+
while (line = Readline.readline('', true))
|
142
|
+
unless line =~ /^[0-9]/
|
143
|
+
system('stty', stty_save) # Restore
|
144
|
+
exit
|
145
|
+
end
|
146
|
+
line = line.to_i
|
147
|
+
return res[line - 1] if line.positive? && line <= res.length
|
148
|
+
|
149
|
+
warn 'Out of range'
|
150
|
+
menu(res, title)
|
151
|
+
end
|
152
|
+
rescue Interrupt
|
153
|
+
system('stty', stty_save)
|
154
|
+
exit
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Search the snippets directory for query using find and grep
|
159
|
+
def search(query, folder, try = 0)
|
160
|
+
# First try only search by filenames
|
161
|
+
# Second try search with grep
|
162
|
+
# Third try search with Spotlight name only
|
163
|
+
# Fourth try search with Spotlight all contents
|
164
|
+
cmd = case try
|
165
|
+
when 0
|
166
|
+
%(find "#{folder}" -iregex '#{query.rx}')
|
167
|
+
when 1
|
168
|
+
%(grep -iEl '#{query.rx}' "#{folder}/"*.md)
|
169
|
+
when 2
|
170
|
+
%(mdfind -onlyin "#{folder}" -name '#{query}' 2>/dev/null)
|
171
|
+
when 3
|
172
|
+
%(mdfind -onlyin "#{folder}" '#{query}' 2>/dev/null)
|
173
|
+
end
|
174
|
+
|
175
|
+
matches = `#{cmd}`.strip
|
176
|
+
|
177
|
+
results = []
|
178
|
+
|
179
|
+
if !matches.empty?
|
180
|
+
lines = matches.split(/\n/)
|
181
|
+
lines.each do |l|
|
182
|
+
results << {
|
183
|
+
'title' => File.basename(l, '.*'),
|
184
|
+
'path' => l
|
185
|
+
}
|
186
|
+
end
|
187
|
+
results
|
188
|
+
else
|
189
|
+
return [] if try > 2
|
190
|
+
|
191
|
+
# if no results on the first try, try again searching all text
|
192
|
+
search(query, folder, try + 1)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def highlight_pygments(executable, code, syntax, theme)
|
197
|
+
syntax = syntax.empty? ? '-g' : "-l #{syntax}"
|
198
|
+
`echo #{Shellwords.escape(code)} | #{executable} #{syntax}`
|
199
|
+
end
|
200
|
+
|
201
|
+
def highlight_skylight(executable, code, syntax, theme)
|
202
|
+
return code if syntax.empty?
|
203
|
+
|
204
|
+
`echo #{Shellwords.escape(code)} | #{executable} --syntax #{syntax}`
|
205
|
+
end
|
206
|
+
|
207
|
+
def highlight(code, filename, theme = 'monokai')
|
208
|
+
syntax = syntax_from_extension(filename)
|
209
|
+
|
210
|
+
skylight = `which skylighting`.strip
|
211
|
+
return highlight_skylight(skylight, code, syntax, theme) unless skylight.empty?
|
212
|
+
|
213
|
+
pygments = `which pygmentize`.strip
|
214
|
+
return highlight_pygments(pygments, code, syntax, theme) unless pygments.empty?
|
215
|
+
|
216
|
+
code
|
217
|
+
end
|
218
|
+
|
219
|
+
def ext_to_lang(ext)
|
220
|
+
case ext
|
221
|
+
when /^(as|applescript|scpt)$/
|
222
|
+
'applescript'
|
223
|
+
when /^m$/
|
224
|
+
'objective-c'
|
225
|
+
when /^(pl|perl)$/
|
226
|
+
'perl'
|
227
|
+
when /^py$/
|
228
|
+
'python'
|
229
|
+
when /^(js|jq(uery)?|jxa)$/
|
230
|
+
'javascript'
|
231
|
+
when /^rb$/
|
232
|
+
'ruby'
|
233
|
+
when /^cc$/
|
234
|
+
'c'
|
235
|
+
when /^(ba|fi|z|c)?sh$/
|
236
|
+
'bash'
|
237
|
+
when /^pl$/
|
238
|
+
'perl'
|
239
|
+
else
|
240
|
+
if %w[awk sed css sass scss less cpp php c sh swift html erb json xpath sql htaccess].include?(ext)
|
241
|
+
ext
|
242
|
+
else
|
243
|
+
''
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def syntax_from_extension(filename)
|
249
|
+
ext_to_lang(filename.split(/\./)[1])
|
250
|
+
end
|
251
|
+
|
252
|
+
options = {
|
253
|
+
interactive: true,
|
254
|
+
launchbar: false,
|
255
|
+
output: 'raw',
|
256
|
+
source: $search_path,
|
257
|
+
highlight: false,
|
258
|
+
all: false
|
259
|
+
}
|
260
|
+
|
261
|
+
optparse = OptionParser.new do |opts|
|
262
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] query"
|
263
|
+
|
264
|
+
opts.on('-q', '--quiet', 'Skip menus and display first match') do
|
265
|
+
options[:interactive] = false
|
266
|
+
options[:launchbar] = false
|
267
|
+
end
|
268
|
+
|
269
|
+
opts.on('-a', '--all', 'If a file contains multiple snippets, output all of them (no menu)') do
|
270
|
+
options[:all] = true
|
271
|
+
end
|
272
|
+
|
273
|
+
opts.on('-o', '--output FORMAT', 'Output format (launchbar or raw)') do |outformat|
|
274
|
+
valid = %w[json launchbar lb raw]
|
275
|
+
if outformat.downcase =~ /(launchbar|lb)/
|
276
|
+
options[:launchbar] = true
|
277
|
+
options[:interactive] = false
|
278
|
+
elsif valid.include?(outformat.downcase)
|
279
|
+
options[:output] = outformat.downcase
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
opts.on('-s', '--source FOLDER', 'Snippets folder to search') do |folder|
|
284
|
+
options[:source] = File.expand_path(folder)
|
285
|
+
end
|
286
|
+
|
287
|
+
opts.on('--highlight', 'Use pygments or skylighting to syntax highlight (if installed)') do
|
288
|
+
options[:highlight] = true
|
289
|
+
end
|
290
|
+
|
291
|
+
opts.on('-h', '--help', 'Display this screen') do
|
292
|
+
puts optparse
|
293
|
+
Process.exit 0
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
optparse.parse!
|
298
|
+
|
299
|
+
query = ''
|
300
|
+
|
301
|
+
if options[:launchbar]
|
302
|
+
query = if $stdin.stat.size.positive?
|
303
|
+
$stdin.read.force_encoding('utf-8')
|
304
|
+
else
|
305
|
+
ARGV.join(' ')
|
306
|
+
end
|
307
|
+
elsif ARGV.length
|
308
|
+
query = ARGV.join(' ')
|
309
|
+
end
|
310
|
+
|
311
|
+
query = CGI.unescape(query)
|
312
|
+
|
313
|
+
if query.strip.empty?
|
314
|
+
puts 'No search query'
|
315
|
+
puts optparse
|
316
|
+
Process.exit 1
|
317
|
+
end
|
318
|
+
|
319
|
+
results = search(query, options[:source], 0)
|
320
|
+
|
321
|
+
if options[:launchbar]
|
322
|
+
output = []
|
323
|
+
|
324
|
+
if results.empty?
|
325
|
+
out = {
|
326
|
+
'title' => 'No matching snippets found'
|
327
|
+
}.to_json
|
328
|
+
puts out
|
329
|
+
Process.exit
|
330
|
+
end
|
331
|
+
|
332
|
+
results.each do |result|
|
333
|
+
input = IO.read(result['path'])
|
334
|
+
snippets = input.snippets
|
335
|
+
next if snippets.empty?
|
336
|
+
|
337
|
+
children = []
|
338
|
+
|
339
|
+
if snippets.length == 1
|
340
|
+
output << {
|
341
|
+
'title' => result['title'],
|
342
|
+
'path' => result['path'],
|
343
|
+
'action' => 'copyIt',
|
344
|
+
'actionArgument' => snippets[0]['code'],
|
345
|
+
'label' => 'Copy'
|
346
|
+
}
|
347
|
+
next
|
348
|
+
end
|
349
|
+
|
350
|
+
snippets.each { |s|
|
351
|
+
children << {
|
352
|
+
'title' => s['title'],
|
353
|
+
'path' => result['path'],
|
354
|
+
'action' => 'copyIt',
|
355
|
+
'actionArgument' => s['code'],
|
356
|
+
'label' => 'Copy'
|
357
|
+
}
|
358
|
+
}
|
359
|
+
|
360
|
+
output << {
|
361
|
+
'title' => result['title'],
|
362
|
+
'path' => result['path'],
|
363
|
+
'children' => children
|
364
|
+
}
|
365
|
+
end
|
366
|
+
|
367
|
+
puts output.to_json
|
368
|
+
else
|
369
|
+
filepath = nil
|
370
|
+
if results.empty?
|
371
|
+
warn 'No results'
|
372
|
+
Process.exit 0
|
373
|
+
elsif results.length == 1 || !options[:interactive]
|
374
|
+
filepath = results[0]['path']
|
375
|
+
input = IO.read(filepath)
|
376
|
+
else
|
377
|
+
answer = menu(results, 'Select a file')
|
378
|
+
filepath = answer['path']
|
379
|
+
input = IO.read(filepath)
|
380
|
+
end
|
381
|
+
|
382
|
+
snippets = input.snippets
|
383
|
+
|
384
|
+
if snippets.empty?
|
385
|
+
warn 'No snippets found'
|
386
|
+
Process.exit 0
|
387
|
+
elsif snippets.length == 1 || !options[:interactive]
|
388
|
+
if options[:output] == 'json'
|
389
|
+
$stdout.puts snippets.to_json
|
390
|
+
else
|
391
|
+
snippets.each do |snip|
|
392
|
+
code = snip['code']
|
393
|
+
code = highlight(code, filepath) if options[:highlight]
|
394
|
+
$stdout.puts code
|
395
|
+
end
|
396
|
+
end
|
397
|
+
elsif snippets.length > 1
|
398
|
+
if options[:all]
|
399
|
+
if options[:output] == 'json'
|
400
|
+
$stdout.puts snippets.to_json
|
401
|
+
else
|
402
|
+
snippets.each do |snippet|
|
403
|
+
$stdout.puts snippet['title']
|
404
|
+
$stdout.puts '------'
|
405
|
+
$stdout.puts snippet['code']
|
406
|
+
$stdout.puts
|
407
|
+
end
|
408
|
+
end
|
409
|
+
else
|
410
|
+
answer = menu(snippets, 'Select snippet')
|
411
|
+
if options[:output] == 'json'
|
412
|
+
$stdout.puts answer.to_json
|
413
|
+
else
|
414
|
+
code = answer['code']
|
415
|
+
code = highlight(code, filepath) if options[:highlight]
|
416
|
+
$stdout.puts code
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
data/lib/snibbets/array.rb
CHANGED
data/lib/snibbets/highlight.rb
CHANGED
@@ -41,8 +41,24 @@ module Snibbets
|
|
41
41
|
# `echo #{Shellwords.escape(code)} | #{executable} #{theme}--syntax #{syntax}`
|
42
42
|
end
|
43
43
|
|
44
|
+
def highlight_fences(code, filename, syntax)
|
45
|
+
content = code.dup
|
46
|
+
|
47
|
+
content.fences.each do |f|
|
48
|
+
rx = Regexp.new(Regexp.escape(f[:code]))
|
49
|
+
highlighted = highlight(f[:code].gsub(/\\k</, '\k\<'), filename, f[:lang] || syntax).strip
|
50
|
+
code.sub!(/#{rx}/, highlighted)
|
51
|
+
end
|
52
|
+
|
53
|
+
Snibbets.options[:all_notes] ? code.gsub(/k\\</, 'k<') : code.gsub(/k\\</, 'k<').clean_code
|
54
|
+
end
|
55
|
+
|
44
56
|
def highlight(code, filename, syntax, theme = nil)
|
45
|
-
|
57
|
+
unless $stdout.isatty
|
58
|
+
return Snibbets.options[:all_notes] && code.replace_blocks[0].notes? ? code : code.clean_code
|
59
|
+
end
|
60
|
+
|
61
|
+
return highlight_fences(code, filename, syntax) if code.fenced?
|
46
62
|
|
47
63
|
theme ||= Snibbets.options[:highlight_theme] || 'monokai'
|
48
64
|
syntax ||= Lexers.syntax_from_extension(filename)
|
data/lib/snibbets/string.rb
CHANGED
@@ -47,6 +47,28 @@ module Snibbets
|
|
47
47
|
count > 1 && count.even?
|
48
48
|
end
|
49
49
|
|
50
|
+
def blocks
|
51
|
+
replace_blocks[1].count
|
52
|
+
end
|
53
|
+
|
54
|
+
def blocks?
|
55
|
+
blocks.positive?
|
56
|
+
end
|
57
|
+
|
58
|
+
def notes?
|
59
|
+
replace_blocks[0].split("\n").notes.positive?
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return array of fenced code blocks
|
63
|
+
def fences
|
64
|
+
return [] unless fenced?
|
65
|
+
|
66
|
+
rx = /(?mi)^(?<fence>`{3,})(?<lang> *\S+)? *\n(?<code>[\s\S]*?)\n\k<fence> *(?=\n|\Z)/
|
67
|
+
matches = []
|
68
|
+
scan(rx) { matches << Regexp.last_match }
|
69
|
+
matches.each_with_object([]) { |m, fenced| fenced.push({ code: m['code'], lang: m['lang'] }) }
|
70
|
+
end
|
71
|
+
|
50
72
|
def indented?
|
51
73
|
self =~ /^( {4,}|\t+)/
|
52
74
|
end
|
@@ -61,7 +83,7 @@ module Snibbets
|
|
61
83
|
|
62
84
|
# if it's a fenced code block, just discard the fence and everything
|
63
85
|
# outside it
|
64
|
-
if block.fenced?
|
86
|
+
if block.fenced?
|
65
87
|
code_blocks = block.scan(/(`{3,})(\w+)?\s*\n(.*?)\n\1/m)
|
66
88
|
code_blocks.map! { |b| b[2].strip }
|
67
89
|
return code_blocks.join("\n\n")
|
@@ -142,23 +164,29 @@ module Snibbets
|
|
142
164
|
|
143
165
|
parts.each do |part|
|
144
166
|
lines = part.split(/\n/).strip_empty
|
145
|
-
next if lines.blocks.zero?
|
146
167
|
|
147
|
-
|
168
|
+
notes = part.notes?
|
148
169
|
|
149
|
-
|
150
|
-
|
170
|
+
next if lines.blocks.zero? && !notes
|
171
|
+
|
172
|
+
title = if lines.count > 1 && lines[0] !~ /<block\d+>/ && lines[0] =~ /^ +/
|
173
|
+
lines.shift.strip.sub(/[.:]$/, '')
|
151
174
|
else
|
152
|
-
|
175
|
+
'Default snippet'
|
153
176
|
end
|
154
177
|
|
155
|
-
|
178
|
+
block = lines.join("\n").gsub(/<(block\d+)>/) do
|
179
|
+
code = code_blocks[Regexp.last_match(1)].strip_empty
|
180
|
+
lang, code = parse_lang_marker(code)
|
181
|
+
"\n```#{lang}\n#{code.strip}\n```"
|
182
|
+
end
|
156
183
|
|
157
|
-
lang,
|
158
|
-
code = block.clean_code
|
184
|
+
lang, code = parse_lang_marker(block)
|
159
185
|
|
160
186
|
next unless code && !code.empty?
|
161
187
|
|
188
|
+
# code = code.clean_code unless notes || code.fences.count > 1
|
189
|
+
|
162
190
|
sections << {
|
163
191
|
'title' => title,
|
164
192
|
'code' => code.strip_empty,
|
data/lib/snibbets/version.rb
CHANGED
data/lib/snibbets.rb
CHANGED
@@ -116,7 +116,6 @@ module Snibbets
|
|
116
116
|
notebook = Snibbets.options[:source].gsub(/ /, '%20')
|
117
117
|
note = ERB::Util.url_encode(File.basename(filepath, '.md'))
|
118
118
|
url = "x-nvultra://open?notebook=#{notebook}¬e=#{note}"
|
119
|
-
puts url
|
120
119
|
`open '#{url}'`
|
121
120
|
end
|
122
121
|
|
@@ -287,6 +286,7 @@ module Snibbets
|
|
287
286
|
end
|
288
287
|
code = snip['code']
|
289
288
|
lang = snip['language']
|
289
|
+
|
290
290
|
print(code, filepath, lang)
|
291
291
|
end
|
292
292
|
end
|
@@ -350,14 +350,14 @@ module Snibbets
|
|
350
350
|
end
|
351
351
|
|
352
352
|
def print(output, filepath, syntax = nil)
|
353
|
+
if Snibbets.options[:copy]
|
354
|
+
OS.copy(Snibbets.options[:all_notes] ? output : output.clean_code)
|
355
|
+
warn 'Copied to clipboard'
|
356
|
+
end
|
353
357
|
if Snibbets.options[:highlight] && Snibbets.options[:output] == 'raw'
|
354
358
|
$stdout.puts(Highlight.highlight(output, filepath, syntax))
|
355
359
|
else
|
356
|
-
$stdout.puts(output)
|
357
|
-
end
|
358
|
-
if Snibbets.options[:copy]
|
359
|
-
OS.copy(output)
|
360
|
-
$stderr.puts "Copied to clipboard"
|
360
|
+
$stdout.puts(Snibbets.options[:all_notes] ? output : output.clean_code)
|
361
361
|
end
|
362
362
|
end
|
363
363
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
current_ver = `rake cver`
|
5
|
+
src = 'src/_README.md'
|
6
|
+
dest = 'README.md'
|
7
|
+
|
8
|
+
readme = IO.read(src).force_encoding('ASCII-8BIT').encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
|
9
|
+
|
10
|
+
content = readme.match(/(?<=\<!--README-->)(.*?)(?=\<!--END README-->)/m)[0]
|
11
|
+
|
12
|
+
content.gsub!(/<!--VER-->(.*?)<!--END VER-->/, current_ver)
|
13
|
+
content.gsub!(/<!--GITHUB-->(.*?)<!--END GITHUB-->/m, '\1')
|
14
|
+
content.gsub!(/<!--JEKYLL(.*?)-->/m, '')
|
15
|
+
|
16
|
+
content.gsub!(/^@cli\((.*?)\)/) do
|
17
|
+
cmd = Regexp.last_match(1)
|
18
|
+
`#{cmd}`.strip.gsub(/\n{2,}/, "\n\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
File.open(dest, 'w') { |f| f.puts(content) }
|
22
|
+
|
23
|
+
Process.exit 0
|
data/snibbets.gemspec
CHANGED
@@ -27,9 +27,9 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.bindir = "bin"
|
28
28
|
spec.executables << 'snibbets'
|
29
29
|
|
30
|
-
spec.files = Dir
|
31
|
-
|
32
|
-
|
30
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
31
|
+
`git ls-files -z`.split("\x0").reject { |f| f.strip =~ %r{^((test|spec|features)/|\.git|buildnotes|.*\.taskpaper)} }
|
32
|
+
end
|
33
33
|
|
34
34
|
spec.add_development_dependency "bundler", "~> 2.0"
|
35
35
|
spec.add_development_dependency "awesome_print", "~> 1.9"
|
@@ -1,22 +1,20 @@
|
|
1
|
+
# Snibbets
|
1
2
|
|
2
|
-
|
3
|
+
<!--README-->
|
4
|
+
<!--GITHUB-->
|
3
5
|
[![RubyGems.org](https://img.shields.io/gem/v/snibbets)](https://rubygems.org/gems/snibbets)
|
4
|
-
<<<<<<< HEAD
|
5
|
-
[![GitHub Actions](https://github.com/ttscoff/snibbets/actions/workflows/check.yml/badge.svg)](https://github.com/ttscoff/snibbets/actions/workflows/check.yml)
|
6
|
-
=======
|
7
6
|
<!-- [![GitHub Actions](https://github.com/ttscoff/snibbets/actions/workflows/check.yml/badge.svg)](https://github.com/ttscoff/snibbets/actions/workflows/check.yml) -->
|
8
|
-
|
9
|
-
|
7
|
+
<!--END GITHUB-->
|
10
8
|
A tool for accessing code snippets contained in a folder of plain text Markdown files.
|
11
9
|
|
12
10
|
Snibbets allows me to keep code snippets in raw files, not relying on a dedicated code snippet app. I can collect and edit my snippets using a text editor, nvALT (nvUltra), or simply by saving snippets from my clipboard to a text file using *NIX redirection on the command line. I can add descriptive names and extended descriptions/notes to code snippets using standard Markdown.
|
13
11
|
|
14
12
|
What Snibbets does is simply allow a quick search for a specific snippet that I can either output to the terminal, pipe to my clipboard, or access via LaunchBar (via the included LaunchBar Action). It's basically a wrapper for `find` and `grep` with the ability to separate code blocks from other text in my Markdown files.
|
15
13
|
|
16
|
-
|
14
|
+
<!--GITHUB-->
|
17
15
|
![Snibbets in action](https://cdn3.brettterpstra.com/uploads/2023/04/snibbets2.gif)
|
18
|
-
|
19
|
-
|
16
|
+
<!--END GITHUB-->
|
17
|
+
<!--JEKYLL{% gif /uploads/2023/04/snibbets2.gif %}-->
|
20
18
|
|
21
19
|
## Collecting Snippets
|
22
20
|
|
@@ -28,7 +26,7 @@ The name of the file should be the description of the snippet, at least in the c
|
|
28
26
|
|
29
27
|
You can combine multiple snippets in a file, though. For example, I have a file called 'Ruby hash snippets.rb.md'. That file contains an array of useful snippets, and each one has a descriptive title in an h3 header above it. Those (ATX) headers are used to split the file, and when you search from the command line, you'll get a menu of all of the snippets in the selected file. (And if you have [fzf](https://github.com/junegunn/fzf) or [gum](https://github.com/charmbracelet/gum) installed, you can quickly filter through with fuzzy searching and find exactly what you need.)
|
30
28
|
|
31
|
-
If a file contains multiple snippets, they should be separated by ATX-style headers (one or more `#`) describing the snippets. Additional
|
29
|
+
If a file contains multiple snippets, they should be separated by ATX-style headers (one or more `#`) describing the snippets. Additional descriptions and notes can be included outside of the code block. Notes are not output on the console, only the code is displayed. If you want a note to be included in console output, make it a blockquote by preceding it with `>`.
|
32
30
|
|
33
31
|
A file titled `unix find.bash.md`:
|
34
32
|
|
@@ -49,22 +47,22 @@ A file titled `unix find.bash.md`:
|
|
49
47
|
|
50
48
|
find /dir/dir -type f -mtime +540 -mtime -720 -printf \"%p\",\"%s\",\"%AD\",|"%TD\"\\n > /dir/dir/output.csv
|
51
49
|
|
52
|
-
You can include MultiMarkdown metadata in your snippets, either in a YAML block or just at the top of the file with raw key/value pairs. I mostly use this for adding tags, which are then synced to macOS tags when I save. It makes it easy to search for snippets in [nvUltra](https://nvultra.com/), and also allows you to do searches like `snibbets tag:javascript url parser`
|
50
|
+
You can include MultiMarkdown metadata in your snippets, either in a YAML block or just at the top of the file with raw key/value pairs. I mostly use this for adding tags, which are then synced to macOS tags when I save. It makes it easy to search for snippets in [nvUltra](https://nvultra.com/), and also allows you to do searches like `snibbets tag:javascript url parser` with Snibbets.
|
53
51
|
|
54
52
|
## CLI
|
55
53
|
|
56
54
|
### Dependencies
|
57
55
|
|
58
|
-
Snibbets requires Ruby 3.0+. On recent versions of macOS, this is not included by default. You can install it via the Command Line Tools from Apple. On macOS and most other systems, you can use something like [Homebrew], [rbenv], [rvm], or [asdf] to install Ruby 3.
|
56
|
+
Snibbets requires Ruby 3.0+. On recent versions of macOS, this is not included by default. You can install it via the Command Line Tools from Apple. On macOS and most other systems, you can also use something like [Homebrew], [rbenv], [rvm], or [asdf] to install Ruby 3.
|
59
57
|
|
60
58
|
If available, menus are generated by [fzf] or [gum]. If neither are available, a basic Readline menu system will be displayed, so neither are required, just nice to have as they provide fuzzy filtering, scrolling, and type-ahead completion.
|
61
59
|
|
62
|
-
[homebrew]: https://brew.sh/ "Homebrew
|
60
|
+
[homebrew]: https://brew.sh/ "Homebrew—The Missing Package Manager for macOS (or Linux)"
|
63
61
|
[rbenv]: https://github.com/rbenv/rbenv "rbenv/rbenv:Manage your app's Ruby environment"
|
64
62
|
[rvm]: https://rvm.io/ "Ruby Version Manager"
|
65
63
|
[asdf]: https://asdf-vm.com/ "ASDF environment manager"
|
66
64
|
[fzf]: https://github.com/junegunn/fzf "junegunn/fzf:A command-line fuzzy finder"
|
67
|
-
[gum]: https://github.com/charmbracelet/gum "charmbracelet/gum:A tool for glamorous shell scripts
|
65
|
+
[gum]: https://github.com/charmbracelet/gum "charmbracelet/gum:A tool for glamorous shell scripts 🎀"
|
68
66
|
|
69
67
|
### Installation
|
70
68
|
|
@@ -106,14 +104,14 @@ Set the `source` key to the folder where you keep your Markdown snippets. Option
|
|
106
104
|
|
107
105
|
The `all` setting determines how Snibbets handles files containing multiple snippets. If `all` is true, then it will always display every snippet in the selected file. If false, it will offer a menu and let you choose which snippet to display. You can use `--all` on the command line to just enable this once.
|
108
106
|
|
107
|
+
By default, Snibbets displays only the code from each snippet (and optionally block quotes, see below). If you set `all_notes` to true, then the full content of each snippet containing a code block will be returned, allowing you to see additional notes on the command line. This can be toggled at runtime with `--notes` or `--no-notes`.
|
108
|
+
|
109
109
|
The `copy` setting determines whether the output is copied to the clipboard in addition to being displayed on STDOUT. This is the equivalent of running `snibbets QUERY | pbcopy` (macOS) or `snibbets QUERY | xclip` (Linux). This can be enabled for just one run with `--copy` on the command line. Setting it to true in the config will copy to the clipboard every time a snippet is displayed. On Mac this will work automatically, on Windows/Linux you may need to [install `xclip` or `xsel`][xclip].
|
110
110
|
|
111
111
|
[xclip]: https://ostechnix.com/access-clipboard-contents-using-xclip-and-xsel-in-linux/
|
112
112
|
|
113
113
|
The `editor` setting is used to open the config file, and to open snippets for editing when using the `--edit` flag. This setting can be any command line utility (`code`, `subl`, `vim`, `nano`, etc.), or on macOS it can be an application name (`BBEdit`, `VS Code`, etc.) or a bundle identifier (`com.sublimetext.4`, `com.microsoft.VSCode`, etc.). If no editor is set, then the file will be opened by whatever the system default is (using `open` on macOS, `start` on Windows, or `xdg-open`on Linux).
|
114
114
|
|
115
|
-
The `highlight` key turns on syntax highlighting. This requires that either `pygmentize` or `skyligting` is available on your system (both available via package managers like Homebrew). This feature is still in development and results may be mixed.
|
116
|
-
|
117
115
|
The `include_blockquotes` setting determines whether blockquotes are included in the output. By default, Snibbets removes everything other than code blocks (indented or fenced) from the output it displays. But if you want to include a note that you'll see on the command line, you can put it in a block quote by preceding each line you want to preserve with a right angle bracket (`>`).
|
118
116
|
|
119
117
|
The `interactive` setting determines whether menus will be displayed. This should generally be true, but if you want silent operation that just displays the best match automatically, set it to false.
|
@@ -122,26 +120,48 @@ The `menus` setting will determine what method is used for displaying interactiv
|
|
122
120
|
|
123
121
|
The `name_only` key will permanently set Snibbets to only search for snippets by their filename rather than examining their contents. You can enable this at runtime using `--name-only` in the command.
|
124
122
|
|
123
|
+
#### Syntax Highlighting
|
124
|
+
|
125
|
+
The `highlight` key turns on syntax highlighting. This requires that either `pygmentize` or `skylighting` is available on your system (both available via package managers like Homebrew). This feature is still in development and results may be mixed. You can also set `highlighter` to `pygments` or `skylight` to force using one highlighter over the other.
|
126
|
+
|
127
|
+
Highlighting using Skylighting requires that your snippets be named with extra extensions defining the lexer to use. The last extension before `.md` (or whatever your snippet extension is set to) should be the one that the highlighter will recognize as a valid lexer, e.g. `my code.jquery.js.md`.
|
128
|
+
|
129
|
+
You can also define languages in your fenced code blocks by putting the lexer name right after the opening fence. When defining multiple snippets in one file that are of different languages, this method will ensure that each one is properly highlighted.
|
130
|
+
|
131
|
+
If you don't use either extensions or fenced code labels with Skylighting, code won't get highlighted.
|
132
|
+
|
133
|
+
To define a snippet as python code, for example:
|
134
|
+
|
135
|
+
```python
|
136
|
+
class EmlServer(SMTPServer):
|
137
|
+
no = 0
|
138
|
+
def process_message(self, peer, mailfrom, rcpttos, data):
|
139
|
+
filename = '%s-%d.eml' % (datetime.now().strftime('%Y%m%d%H%M%S'),
|
140
|
+
self.no)
|
141
|
+
f = open(filename, 'w')
|
142
|
+
```
|
143
|
+
|
144
|
+
You can also define a color scheme with `highlight_theme`. If you're using Pygments, run `pygmentize -L styles` to see available options. If you're using Skylighting, you can reference any theme in the [KDE repository]. Skylighting themes are included in Snibbets and can be referenced by their filename without `.theme`, or you can install your own themes and reference them with a full path. (I recommend `nord` when using Sylighting.)
|
145
|
+
|
146
|
+
[KDE repository]: https://github.com/KDE/syntax-highlighting/tree/master/data/themes
|
147
|
+
|
148
|
+
You can turn highlighting on or off for a single run using `--highlight` or `--no-highlight`. Syntax highlighting definitely affects copyable output, so it's automatically disabled when piping/redirecting output. When using `--copy`, the code sent to the clipboard is not highlighted.
|
149
|
+
|
150
|
+
##### Installing a Syntax Highlighter
|
151
|
+
|
152
|
+
Snibbet's implementation of Skylighting has limited but better-looking themes, and has some lexers that Pygments lacks. However, Pygments has _more_ lexers and a wider array of themes. It also can determine the target syntax automatically better than Skylighting (which requires the syntax to be specified -- it's pulled from the extensions of your snippets), which is why Pygments is the default if it's installed and you don't configure it otherwise.
|
153
|
+
|
154
|
+
- Install [Skylighting] with [Homebrew] (`brew install skylighting`) or [apt-get].
|
155
|
+
- Install [Pygments] using [Homebrew] (`brew install pygments`) or `pip install pygments`.
|
156
|
+
|
157
|
+
[Skylighting]: https://github.com/jgm/skylighting
|
158
|
+
[apt-get]: https://installati.one/install-skylighting-ubuntu-22-04/
|
159
|
+
[Pygments]: https://pygments.org/
|
160
|
+
|
125
161
|
### Usage
|
126
162
|
|
127
163
|
```
|
128
|
-
|
129
|
-
|
130
|
-
Usage: snibbets [options] query
|
131
|
-
-a, --all If a file contains multiple snippets, output all of them (no menu)
|
132
|
-
-c, --[no-]copy Copy the output to the clibpoard (also displays on STDOUT)
|
133
|
-
-e, --edit Open the selected snippet in your configured editor
|
134
|
-
-n, --[no-]name-only Only search file names, not content
|
135
|
-
-o, --output FORMAT Output format (json|launchbar|*raw)
|
136
|
-
-p, --paste, --new Interactively create a new snippet from clipboard contents (Mac only)
|
137
|
-
-q, --quiet Skip menus and display first match
|
138
|
-
-s, --source FOLDER Snippets folder to search
|
139
|
-
--configure Open the configuration file in your default editor
|
140
|
-
--[no-]blockquotes Include block quotes in output
|
141
|
-
--highlight Use pygments or skylighting to syntax highlight (if installed)
|
142
|
-
--save Save the current command line options to the YAML configuration
|
143
|
-
-h, --help Display this screen
|
144
|
-
-v, --version Display version information
|
164
|
+
@cli(bundle exec bin/snibbets -h)
|
145
165
|
```
|
146
166
|
|
147
167
|
If your Snippets folder is set in the config, simply running `snibbets [search query]` will perform the search and output the code blocks, presenting a menu if more than one match is found or the target file contains more than one snippet. Selected contents are output raw to STDOUT.
|
@@ -175,7 +195,7 @@ Any time you specify things like a source folder with the `--source` flag, or tu
|
|
175
195
|
|
176
196
|
_I'm currently reworking the LaunchBar action, and it doesn't function very well at this time. I'll update when I have a chance._
|
177
197
|
|
178
|
-
### Installation
|
198
|
+
<!-- ### Installation
|
179
199
|
|
180
200
|
The LaunchBar action can be installed simply by double clicking the `.lbaction` file in Finder. The CLI is not required for the LaunchBar action to function.
|
181
201
|
|
@@ -183,4 +203,5 @@ Once installed, run the action (type `snib` and hit return on the result) to sel
|
|
183
203
|
|
184
204
|
### Usage
|
185
205
|
|
186
|
-
Type `snib` to bring the Action up, then hit Space to enter your query text. Matching files will be presented. If the selected file contains more than one snippet, a list of snippets (based on ATX headers in the file) will be presented as a child menu. Selecting a snippet and hitting return will copy the associated code block to the clipboard.
|
206
|
+
Type `snib` to bring the Action up, then hit Space to enter your query text. Matching files will be presented. If the selected file contains more than one snippet, a list of snippets (based on ATX headers in the file) will be presented as a child menu. Selecting a snippet and hitting return will copy the associated code block to the clipboard. -->
|
207
|
+
<!--END README-->
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snibbets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.32
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -238,17 +238,23 @@ extensions: []
|
|
238
238
|
extra_rdoc_files:
|
239
239
|
- README.md
|
240
240
|
files:
|
241
|
+
- ".devcontainer/Dockerfile"
|
242
|
+
- ".devcontainer/devcontainer.json"
|
243
|
+
- ".editorconfig"
|
244
|
+
- ".irbrc"
|
245
|
+
- ".rspec"
|
246
|
+
- ".ruby-version"
|
241
247
|
- CHANGELOG.md
|
242
248
|
- Gemfile
|
243
249
|
- Gemfile.lock
|
244
|
-
- Gemfile.lock.orig
|
245
250
|
- LICENSE.txt
|
246
251
|
- README.md
|
247
|
-
- README.md.orig
|
248
252
|
- README.rdoc
|
249
253
|
- Rakefile
|
254
|
+
- Snibbets.lbaction/Contents/Info.plist
|
255
|
+
- Snibbets.lbaction/Contents/Scripts/default.js
|
256
|
+
- Snibbets.lbaction/Contents/Scripts/snibbets.rb
|
250
257
|
- bin/snibbets
|
251
|
-
- buildnotes.md
|
252
258
|
- lib/snibbets.rb
|
253
259
|
- lib/snibbets/array.rb
|
254
260
|
- lib/snibbets/config.rb
|
@@ -259,6 +265,7 @@ files:
|
|
259
265
|
- lib/snibbets/menu.rb
|
260
266
|
- lib/snibbets/os.rb
|
261
267
|
- lib/snibbets/string.rb
|
268
|
+
- lib/snibbets/todo_spec.rb
|
262
269
|
- lib/snibbets/version.rb
|
263
270
|
- lib/snibbets/which.rb
|
264
271
|
- lib/themes/atom-one-dark.theme
|
@@ -287,8 +294,10 @@ files:
|
|
287
294
|
- lib/themes/solarized-dark.theme
|
288
295
|
- lib/themes/solarized-light.theme
|
289
296
|
- lib/themes/vim-dark.theme
|
297
|
+
- scripts/fixreadme.rb
|
290
298
|
- snibbets.gemspec
|
291
|
-
-
|
299
|
+
- src/_README.md
|
300
|
+
- yard_templates/default/method_details/setup.rb
|
292
301
|
homepage: https://github.com/ttscoff/snibbets
|
293
302
|
licenses:
|
294
303
|
- MIT
|
data/Gemfile.lock.orig
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
snibbets (2.0.10)
|
5
|
-
tty-which (~> 0.5, >= 0.5.0)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
ansi (1.5.0)
|
11
|
-
ast (2.4.2)
|
12
|
-
awesome_print (1.9.2)
|
13
|
-
diff-lcs (1.5.0)
|
14
|
-
docile (1.4.0)
|
15
|
-
gem-release (2.2.2)
|
16
|
-
json (2.6.3)
|
17
|
-
language_server-protocol (3.17.0.3)
|
18
|
-
multi_json (1.15.0)
|
19
|
-
parallel (1.22.1)
|
20
|
-
parse_gemspec (1.0.0)
|
21
|
-
parse_gemspec-cli (1.0.0)
|
22
|
-
multi_json
|
23
|
-
parse_gemspec
|
24
|
-
thor
|
25
|
-
parser (3.2.2.0)
|
26
|
-
ast (~> 2.4.1)
|
27
|
-
rainbow (3.1.1)
|
28
|
-
rake (13.0.6)
|
29
|
-
<<<<<<< HEAD
|
30
|
-
rdoc (6.3.1)
|
31
|
-
=======
|
32
|
-
rdoc (6.3.3)
|
33
|
-
>>>>>>> af6f234 (Update rdoc)
|
34
|
-
regexp_parser (2.7.0)
|
35
|
-
rexml (3.2.5)
|
36
|
-
rspec (3.12.0)
|
37
|
-
rspec-core (~> 3.12.0)
|
38
|
-
rspec-expectations (~> 3.12.0)
|
39
|
-
rspec-mocks (~> 3.12.0)
|
40
|
-
rspec-core (3.12.1)
|
41
|
-
rspec-support (~> 3.12.0)
|
42
|
-
rspec-expectations (3.12.2)
|
43
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
44
|
-
rspec-support (~> 3.12.0)
|
45
|
-
rspec-mocks (3.12.5)
|
46
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
47
|
-
rspec-support (~> 3.12.0)
|
48
|
-
rspec-support (3.12.0)
|
49
|
-
rubocop (1.48.1)
|
50
|
-
json (~> 2.3)
|
51
|
-
parallel (~> 1.10)
|
52
|
-
parser (>= 3.2.0.0)
|
53
|
-
rainbow (>= 2.2.2, < 4.0)
|
54
|
-
regexp_parser (>= 1.8, < 3.0)
|
55
|
-
rexml (>= 3.2.5, < 4.0)
|
56
|
-
rubocop-ast (>= 1.26.0, < 2.0)
|
57
|
-
ruby-progressbar (~> 1.7)
|
58
|
-
unicode-display_width (>= 2.4.0, < 3.0)
|
59
|
-
rubocop-ast (1.28.0)
|
60
|
-
parser (>= 3.2.1.0)
|
61
|
-
rubocop-performance (1.16.0)
|
62
|
-
rubocop (>= 1.7.0, < 2.0)
|
63
|
-
rubocop-ast (>= 0.4.0)
|
64
|
-
ruby-progressbar (1.13.0)
|
65
|
-
simplecov (0.22.0)
|
66
|
-
docile (~> 1.1)
|
67
|
-
simplecov-html (~> 0.11)
|
68
|
-
simplecov_json_formatter (~> 0.1)
|
69
|
-
simplecov-console (0.9.1)
|
70
|
-
ansi
|
71
|
-
simplecov
|
72
|
-
terminal-table
|
73
|
-
simplecov-html (0.12.3)
|
74
|
-
simplecov_json_formatter (0.1.4)
|
75
|
-
standard (1.26.0)
|
76
|
-
language_server-protocol (~> 3.17.0.2)
|
77
|
-
rubocop (~> 1.48.1)
|
78
|
-
rubocop-performance (~> 1.16.0)
|
79
|
-
terminal-table (3.0.2)
|
80
|
-
unicode-display_width (>= 1.1.1, < 3)
|
81
|
-
thor (1.2.1)
|
82
|
-
tty-which (0.5.0)
|
83
|
-
unicode-display_width (2.4.2)
|
84
|
-
webrick (1.7.0)
|
85
|
-
yard (0.9.28)
|
86
|
-
webrick (~> 1.7.0)
|
87
|
-
|
88
|
-
PLATFORMS
|
89
|
-
arm64-darwin-20
|
90
|
-
x86_64-linux
|
91
|
-
|
92
|
-
DEPENDENCIES
|
93
|
-
awesome_print (~> 1.9)
|
94
|
-
bundler (~> 2.0)
|
95
|
-
gem-release (~> 2.2)
|
96
|
-
parse_gemspec-cli (~> 1.0)
|
97
|
-
rake (~> 13.0)
|
98
|
-
rdoc (~> 6.3.1)
|
99
|
-
rspec (~> 3.0)
|
100
|
-
simplecov (~> 0.21)
|
101
|
-
simplecov-console (~> 0.9)
|
102
|
-
snibbets!
|
103
|
-
standard (~> 1.3)
|
104
|
-
yard (~> 0.9, >= 0.9.26)
|
105
|
-
|
106
|
-
BUNDLED WITH
|
107
|
-
2.2.29
|
data/buildnotes.md
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
template: gem, git, gli, project
|
2
|
-
executable: na
|
3
|
-
readme: src/_README.md
|
4
|
-
changelog: CHANGELOG.md
|
5
|
-
project: snibbets
|
6
|
-
|
7
|
-
# Snibbets
|
8
|
-
|
9
|
-
A plain text snippet manager
|
10
|
-
|
11
|
-
## Develop
|
12
|
-
|
13
|
-
@run(subl .)
|
14
|
-
|
15
|
-
## Dummy
|
16
|
-
|
17
|
-
@run(bundle exec bin/snibbets $@)
|
18
|
-
|
19
|
-
## Deploy
|
20
|
-
|
21
|
-
You no longer need to manually bump the version, it will be incremented when this task runs.
|
22
|
-
|
23
|
-
```run Update Changelog
|
24
|
-
#!/bin/bash
|
25
|
-
|
26
|
-
changelog -u
|
27
|
-
```
|
28
|
-
|
29
|
-
@include(project:Update GitHub README)
|
30
|
-
|
31
|
-
```run Update README
|
32
|
-
#!/bin/bash
|
33
|
-
|
34
|
-
changelog | git commit -a -F -
|
35
|
-
git pull
|
36
|
-
git push
|
37
|
-
```
|
38
|
-
|
39
|
-
@include(gem:Release Gem) Release Gem
|
40
|
-
@include(project:Update Blog Project) Update Blog Project
|
41
|
-
@run(rake bump[patch]) Bump Version
|
42
|
-
|
43
|
-
@run(git commit -am 'Version bump')
|
44
|
-
|
45
|
-
@after
|
46
|
-
Don't forget to publish the website!
|
47
|
-
@end
|
data/snibbets.taskpaper
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
Inbox:
|
2
|
-
- handle multiple code blocks within a section separately for highlighting @maybe @na
|
3
|
-
If a header contains multiple snippets, create an array with a language specifier for each snippet, and then pass the array to the print function to handle individually highlighting each code block. Have a special language specifier for blockquote notes to avoid highlighting them at all.
|
4
|
-
Could possibly just highlight each block as its found, and save an original copy in memory for uncolored output, or just write a decoloring method. Skip highlighting if it's not enabled, but decolor ouput sent to non-tty or --copy.
|
5
|
-
snibbets:
|
6
|
-
Feature Requests:
|
7
|
-
Ideas:
|
8
|
-
Bugs:
|
9
|
-
Archive:
|
10
|
-
Search Definitions:
|
11
|
-
Top Priority @search(@priority = 5 and not @done)
|
12
|
-
High Priority @search(@priority > 3 and not @done)
|
13
|
-
Maybe @search(@maybe)
|
14
|
-
Next @search(@na and not @done and not project = "Archive")
|