-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbangs
More file actions
executable file
·163 lines (139 loc) · 4.84 KB
/
Copy pathbangs
File metadata and controls
executable file
·163 lines (139 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env nix-shell
#! nix-shell -i oil -p coreutils ripgrep handlr gnused xxd
# A ripoff from Duckduckgo bangs.
# Examples:
# ```
# bangs hello there ~g ~aw
# ```
# will open a search result page on Google and Arch Wiki
# TODO:
# - Make the config compatible to bangs database from Duckduckgo.
proc usage() {
cat <<HELP
bangs - a ripoff from Duckduckgo bangs, except
you can open multiple pages in one go.
Usage:
bangs [SEARCH_QUERY...] [BANGS...]
A bang is absolutely necessary to indicate what search pages
to open.
While there is a default config, you should create your own list
by setting a config file at '\${XDG_CONFIG_HOME}/bangs/config.json'.
The config is simply a JSON file with the bang as the key and an
object with 'url' and 'name'.
Examples:
- Google and Duckduckgo search
bangs hello world ~g ~ddg
- Change the bangs prefix
BANGS_PREFIX="--" bangs how to program in python --g --yt
HELP
}
# Simply prints the given string into percent-encoded equivalent.
#
# `urlencode "Hello world"` will give "Hello%20world"
#
# Stolen from https://gist.github.com/cdown/1163649 and https://gist.github.com/cdown/1163649#gistcomment-1256298.
# Just ported it in Oil script.
proc urlencode(msg) {
for (i in 0:len(msg)) {
var char = msg[i]
case $char {
[a-zA-Z0-9.~_-])
printf '%s' $char
;;
*)
printf '%s' $char | xxd -plain -cols 1 | while read :hex { printf '%%%s' $hex }
;;
}
}
}
# `printf` except it prints in the stderr stream.
proc warnf(format, @msg) {
>&2 printf "$format\\n" @msg
}
# The entry point of this program.
proc main {
# Config-related variables.
# For now, there is no system-related config.
# This is primarily a user script, after all. :)
const config_dir = "${XDG_CONFIG_HOME:-"$HOME/.config"}/bangs"
const config_file = "${config_dir}/config.json"
# Note you can configure these variables through the respective environment variables.
const bangs_prefix = "${BANGS_PREFIX:-~}"
const bangs_placeholder = "${BANGS_PLACEHOLDER:-{{{s}}}}"
# These are the default bangs available.
# Bangs are any keys that shouldn't have whitespace characters.
# We'll use this in case there is no user configuration.
#
# We also made the default config to be more flexible with the placeholder.
const default_config = {
'aw': {
'name': 'Arch Wiki',
'url': 'https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=' + bangs_placeholder
},
'gh': {
'name': 'GitHub',
'url': 'https://github.com/search?utf8=%E2%9C%93&q=' + bangs_placeholder
},
'g': {
'name': 'Google',
'url': 'https://www.google.com/search?q=' + bangs_placeholder
},
'so': {
'name': 'Stack Overflow',
'url': 'http://stackoverflow.com/search?q=' + bangs_placeholder
},
'w': {
'name': 'Wikipedia',
'url': 'https://en.wikipedia.org/wiki/Special:Search?search=' + bangs_placeholder
}
}
# Setting up some variables.
const bangs_format = / %start $bangs_prefix !space+ %end /
const valid_bangs = %()
const search_query = %()
# Config file detection.
# Otherwise, we'll just use the default config.
if test -f $config_file {
json read :bangs < $config_file
} else {
var bangs = default_config
}
# Show the usage when no arguments was given like any sane program.
if (len(ARGV) == 0) {
usage
exit 0
}
# Filter out the bangs from the search query.
# The bangs are just words prefixed with a certain sequence of characters.
# We put both bangs and the search query in separate arrays for easier processing.
# E.g., in the search query `hello ~ddg world ~g`, `~ddg~ and `~g` are the bangs.
for i in @ARGV {
# If the argument is not a bang, append in the search query queue.
write -- $i | rg --quiet $bangs_format || {
append :search_query $i
continue
}
# Otherwise, put it in the bangs array.
# Keep in mind, we do throw out bangs that are not in the bangs database.
var bang = $(write -- $i | sed --regexp-extended --expression "s/^${bangs_prefix}//")
if (bang in bangs) {
append :valid_bangs $bang
warnf "%s will be used to search." $bang
} else {
warnf "%s is not found in the database." $bang
}
}
# Encode the query for a consistent formatting.
# Even though this script is in Oil where it has less problems with splitting strings, we still might want to encode the query for a good measure.
var query = join(search_query, " ")
var encoded_query = $(urlencode $query)
warnf "Search query is '%s'" $query
warnf "Encoded form is '%s'" $encoded_query
# Search the query with the given bangs.
for bang in @valid_bangs {
var metadata = bangs[bang]
var url = $(write -- ${metadata['url']} | sed --expression "s/${bangs_placeholder}/${encoded_query}/")
handlr open $url
}
}
main @ARGV