dotfiles/bin/bangs

132 lines
3.3 KiB
Plaintext
Raw Normal View History

2021-06-24 07:19:21 +00:00
#!/usr/bin/env nix-shell
#! nix-shell -i oil -p coreutils ripgrep handlr gnused xxd
# A ripoff from Duckduckgo bangs.
# Examples:
# ```
2021-07-14 11:28:22 +00:00
# bangs hello there ~g ~aw
2021-06-24 07:19:21 +00:00
# ```
# will open a search result page on Google and Arch Wiki
2021-08-08 17:07:46 +00:00
# TODO:
# - Make the config compatible to bangs database from Duckduckgo.
2021-07-14 11:28:22 +00:00
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
}
2021-06-24 07:19:21 +00:00
# These are the default bangs available.
2021-07-14 11:28:22 +00:00
# Bangs are any keys that shouldn't have whitespace characters.
2021-06-24 07:19:21 +00:00
const config_dir = "${XDG_CONFIG_HOME:-"$HOME/.config"}/bangs"
const config_file = "${config_dir}/config.json"
const default_config = {
'aw': {
'name': 'Arch Wiki',
'url': 'https://wiki.archlinux.org/index.php?title=Special%3ASearch&search={{{s}}}'
},
'gh': {
'name': 'GitHub',
'url': 'https://github.com/search?utf8=%E2%9C%93&q={{{s}}}'
},
'g': {
'name': 'Google',
'url': 'https://www.google.com/search?q={{{s}}}'
},
'so': {
'name': 'Stack Overflow',
'url': 'http://stackoverflow.com/search?q={{{s}}}'
},
'w': {
'name': 'Wikipedia',
'url': 'https://en.wikipedia.org/wiki/Special:Search?search={{{s}}}'
}
}
const bangs_prefix = "${BANGS_PREFIX:-~}"
const bangs_placeholder = "${BANGS_PLACEHOLDER:-{{{s}}}}"
2021-07-14 11:28:22 +00:00
const bangs_format = / %start $bangs_prefix !space+ %end /
2021-06-24 07:19:21 +00:00
const valid_bangs = %()
const search_query = %()
2021-07-22 11:24:53 +00:00
# Config file detection.
# Otherwise, we'll just use the default config.
2021-06-24 07:19:21 +00:00
if test -f $config_file {
json read :bangs < $config_file
} else {
var bangs = default_config
}
# Stolen from https://gist.github.com/cdown/1163649 and https://gist.github.com/cdown/1163649#gistcomment-1256298
proc urlencode(msg) {
for (i in 0:len(msg)) {
2021-07-22 11:24:53 +00:00
var char = msg[i]
2021-06-24 07:19:21 +00:00
case $char {
[a-zA-Z0-9.~_-])
printf '%s' $char
;;
*)
printf '%s' $char | xxd -plain -cols 1 | while read :hex { printf '%%%s' $hex }
;;
}
}
}
proc warnf(format, @msg) {
>&2 printf "$format\\n" @msg
}
2021-07-14 11:28:22 +00:00
if (len(ARGV) == 0) {
usage
exit 0
}
2021-06-24 07:19:21 +00:00
for i in @ARGV {
write -- $i | rg --quiet $bangs_format || {
2021-08-08 17:07:46 +00:00
append :search_query $i
2021-06-24 07:19:21 +00:00
continue
}
var bang = $(write -- $i | sed --regexp-extended --expression "s/^${bangs_prefix}//")
if (bang in bangs) {
2021-08-08 17:07:46 +00:00
append :valid_bangs $bang
2021-06-24 07:19:21 +00:00
warnf "%s will be used to search." $bang
} else {
warnf "%s is not found in the database." $bang
}
}
2021-07-22 11:24:53 +00:00
var query = join(search_query, " ")
var encoded_query = $(urlencode $query)
2021-06-24 07:19:21 +00:00
warnf "Search query is '%s'" $query
2021-07-22 11:24:53 +00:00
warnf "Encoded form is '%s'" $encoded_query
2021-06-24 07:19:21 +00:00
for bang in @valid_bangs {
var metadata = bangs[bang]
2021-07-22 11:24:53 +00:00
var url = $(write -- ${metadata['url']} | sed --expression "s/${bangs_placeholder}/${encoded_query}/")
2021-06-24 07:19:21 +00:00
handlr open $url
}