Skip to content

Commit 56ffa76

Browse files
committed
Add option for random line selection
1 parent 3cd963c commit 56ffa76

File tree

3 files changed

+76
-37
lines changed

3 files changed

+76
-37
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ www/:
2525
gif:
2626
gifcut -b1 "$$(capture -Wt20)" "www/img/window-$$(date +%s).gif"
2727

28-
.PHONY: gif lint test unit www
28+
push:
29+
git push github
30+
31+
.PHONY: gif lint push test unit www

cz

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,28 @@ EOF
516516
! ((mis))
517517
}
518518

519+
randline() {
520+
read -r -d '' use <<EOF
521+
randline [OPTIONS]
522+
Select a line at random from input and print it.
523+
EOF
524+
# no options just help
525+
local opt OPTIND OPTARG
526+
while getopts ":h" opt; do
527+
case "$opt" in
528+
*)
529+
printf "%s\\n" "$use" >&2
530+
return 1
531+
;;
532+
esac
533+
done
534+
# read all lines then print one random line
535+
local lines=()
536+
mapfile -t lines
537+
local pick=$(( RANDOM % ${#lines[@]} ))
538+
printf "%s\\n" "${lines[$pick]}";
539+
}
540+
519541
rleval() {
520542
read -r -d '' use <<EOF
521543
rleval [OPTIONS] COMMAND [ARGS ...]
@@ -661,7 +683,7 @@ EOF
661683

662684
cz() {
663685
# version
664-
local ver="0.8.5"
686+
local ver="0.8.6"
665687
# usage
666688
local hows="" use=""
667689
read -r -d '' use <<EOF
@@ -696,7 +718,8 @@ OPTIONS
696718
-0 : Read null terminated lines from input.
697719
-i IN-FILE : Set file from which to read selections instead of stdin.
698720
699-
These options control which line selection utility is used:
721+
These options control how lines are selected:
722+
-w : Pick a line at random.
700723
-x : Use a graphical line selection tool.
701724
-y : Use a terminal line selection tool.
702725
-z TOOL : Use the given line selection tool.
@@ -743,16 +766,17 @@ Pick from lines on stdin.:$ printf "%s\\n" foo bar qux | cz
743766
Accept null delimited input lines.:$ find . -name '*.yml' -print0 | cz -0
744767
Extract useful fields from selected line.:$ cz -q -f 0,5 -d : < /etc/passwd
745768
Safely handle input strings containing shell characters.:$ cz -e 'echo -- {0:}' -i <(printf "%s\\n" '\$USER' '; false' '\$(fortune)' '-e')
769+
Pick a line randomly instead of using interactive selecting.:# printf "%s\\n" {A..Z} | cz -w
746770
Add selection to common commands.:$ cz -r -e 'dig {0} AAAA +short' compgen hostname
747-
Easily define plugins as bash functions.:$ cz_whois() { cz -e 'whois {0}' -f 0 compgen hostname; }; cz whois
771+
Extend plugins with bash functions.:$ cz_whois() { cz -e 'whois {0}' -f 0 compgen hostname; }; cz whois
748772
Select a password and put it on an xclip clipboard.:$ cz pass | cz xclip in
749773
Jump to any descendant directory.:$ cd \$(cz descendant)
750774
Jump to any ancestor directory.:$ cd \$(cz ancestor)
751775
Grab a URL from a paste buffer and open it in a browser.:$ cz xclip out | cz -e 'firefox {0}' uri
752776
Compose plugins to get the contents of any element from any JSON file.:$ cz -e 'cz jq {0}' locate *.json
753777
Compose plugins to get any file under an apparix bookmarked directory.:$ cz -e 'cz find file {1}' apparix
754778
Find a file then open it for editing:$ find . -type f -print0 | cz -0 -r -e 'vim {0}'
755-
Consult the I Ching.:cz -z shuf -uf0,2 unicode character 'Yijing Hexagram Symbols' | sed 's/HEXAGRAM FOR//'
779+
Consult the I Ching.:cz -u -f0,2 -w unicode character 'Yijing Hexagram Symbols' | sed 's/HEXAGRAM FOR//'
756780
EOF
757781
# supported tools
758782
read -r -d '' exes <<EOF
@@ -784,21 +808,21 @@ EOF
784808
IFS=: read -r gfx app _ <<< "${CZ_GUI:-2}"
785809
if [ -z "$DISPLAY" ]; then gfx=0; fi
786810
# set options from the environment
787-
local tpl="${_CZ_TEMPLATE}" # string | command template
788-
local fld="${_CZ_FIELDS}" # string | field selection
789-
local mode="${_CZ_MODE}" # string | indicator for program mode
790-
local help="${_CZ_HELP}" # string | indicator for help requested
791-
local dlm="${_CZ_DELIM:-$IFS}" # string | delimeter to split selected line
792-
local dbg="${_CZ_DEBUG}" # boolean | whether or not write debug info
811+
local tpl="${_CZ_TEMPLATE}" # string | command template
812+
local fld="${_CZ_FIELDS}" # string | field selection
813+
local mode="${_CZ_MODE}" # string | indicator for program mode
814+
local help="${_CZ_HELP}" # string | indicator for help requested
815+
local dlm="${_CZ_DELIM:-$IFS}" # string | delimeter to split selected line
816+
local dbg="${CZ_DEBUG:-$_CZ_DEBUG}" # boolean | whether or not write debug info
793817
# set option defaults
794-
local inp="/dev/stdin" # string | file from which to select a line
795-
local buf=0 # boolean | require buffered stdin for command
796-
local run="" # string | program mode implied by another option
797-
local nul=0 # boolean | whether to read null separated lines
798-
local clr=0 # boolean | whether to refresh cached input lines
818+
local inp="/dev/stdin" # string | file from which to select a line
819+
local buf=0 # boolean | require buffered stdin for command
820+
local run="" # string | program mode implied by another option
821+
local nul=0 # boolean | whether to read null separated lines
822+
local clr=0 # boolean | whether to refresh cached input lines
799823
# accept options
800824
local opt OPTIND OPTARG
801-
while getopts ":cd:e:f:ghHi:klmopqrstuvxyz:0" opt; do
825+
while getopts ":cd:e:f:ghHi:klmopqrstuvwxyz:0" opt; do
802826
case "$opt" in
803827
c) # clear hold caches
804828
clr=1
@@ -859,7 +883,7 @@ EOF
859883
q) # print rendered template from '-f' with variables shell-quoted
860884
mode=1
861885
;;
862-
r) # execute rendered template from '-e'
886+
r) # run rendered command template from '-e'
863887
mode=2
864888
;;
865889
s) # print string from '-e' as command
@@ -871,13 +895,13 @@ EOF
871895
u) # print rendered template from '-f' with variables inserted directly
872896
mode=5
873897
;;
874-
0) # handle null separated input
875-
nul=1
876-
;;
877898
v) # write version
878899
printf "cz %s\\n" "$ver"
879900
return 0
880901
;;
902+
w) # select a random line instead of using an external tool
903+
app="randline"
904+
;;
881905
x) # try to use a graphical tool for line selection
882906
gfx=1
883907
;;
@@ -891,6 +915,9 @@ EOF
891915
return 2
892916
fi
893917
;;
918+
0) # handle null separated input
919+
nul=1
920+
;;
894921
\?) # invalid option?
895922
printf "Bad option: -%s\\n%s\\n" "$OPTARG" "$use" >&2
896923
return 2
@@ -967,6 +994,7 @@ EOF
967994
fi
968995
# read the selection file
969996
local items=() lines=()
997+
if ((dbg)); then printf "READ %(%H:%M:%S)T\\n" -1 >&2; fi
970998
if ((nul)); then
971999
mapfile -d '' -t lines < "$inp"
9721000
mapfile -t items < <(printf "%q\\n" "${lines[@]}")
@@ -981,8 +1009,9 @@ EOF
9811009
fi
9821010
# buffer stdin if reading selection input from another file
9831011
# this is needed to pass pipe input to plugin commands
984-
declare -a stdin
1012+
local stdin=()
9851013
if [[ "$inp" != "/dev/stdin" ]] && ! [ -t 0 ]; then
1014+
if ((dbg)); then printf "IBUF %(%H:%M:%S)T\\n" -1 >&2; fi
9861015
mapfile -t stdin
9871016
# optionally require actual input lines
9881017
if ((buf)) && ! ((${#stdin})); then return 4; fi
@@ -993,7 +1022,8 @@ EOF
9931022
return 0
9941023
fi
9951024
# choose a line using a known program
996-
local out
1025+
local out=""
1026+
if ((dbg)); then printf "PICK %(%H:%M:%S)T\\n" -1 >&2; fi
9971027
out=$(case "$app" in
9981028
choose)
9991029
choose -n 20
@@ -1016,6 +1046,9 @@ EOF
10161046
pick)
10171047
pick
10181048
;;
1049+
randline)
1050+
randline
1051+
;;
10191052
rofi)
10201053
local theme="${CZ_ROFI_THEME:-Paper}"
10211054
rofi -theme "$theme" -i -dmenu -p ""
@@ -1125,7 +1158,7 @@ EOF
11251158
return 4
11261159
fi
11271160
if ((dbg)); then
1128-
printf "# %s ==> %s\\n" "$fld" "$out" >&2
1161+
printf "# %s ==> %s\\n" "$fld" "$cmd" >&2
11291162
fi
11301163
printf "%s\\n" "$cmd"
11311164
;;
@@ -1135,7 +1168,7 @@ EOF
11351168
return 4
11361169
fi
11371170
if ((dbg)); then
1138-
printf "# %s ==> %s\\n" "$fld" "$out" >&2
1171+
printf "# %s ==> %s\\n" "$fld" "$cmd" >&2
11391172
fi
11401173
printf "%s\\n" "$cmd"
11411174
;;
@@ -1152,7 +1185,7 @@ function _cz() {
11521185
# cz has some options
11531186
local opt="" opts
11541187
declare -A opts
1155-
for opt in -{d,e,f,h,i,l,k,m,o,p,q,r,s,t,u,v,x,y,z,0}; do opts["$opt"]=0; done
1188+
for opt in -{d,e,f,h,i,l,k,m,o,p,q,r,s,t,u,v,w,x,y,z,0}; do opts["$opt"]=0; done
11561189
# scan all previous words
11571190
local base="" last="" word="" i=0
11581191
for ((i=1; i < "$COMP_CWORD"; i++)); do
@@ -1212,7 +1245,7 @@ function _cz() {
12121245
COMPREPLY=("${reply[@]}")
12131246
return
12141247
fi
1215-
# TODO maybe complete something specific for a plugin
1248+
# TODO maybe complete something specific for plugins
12161249
case "$base" in
12171250
*) return ;;
12181251
esac
@@ -2599,7 +2632,7 @@ EOF
25992632
printf "Either grep or rg is required!\\n" >&2
26002633
return 5
26012634
fi
2602-
cz -d ':' -f 0 -e "$EDITOR +{1} -- {0}" \
2635+
cz -d ':' -f "0,1" -e "$EDITOR +{1} -- {0}" \
26032636
-i <(printf "%s\\n" "$matches")
26042637
}
26052638
@@ -3079,7 +3112,7 @@ EOF
30793112
| jq -r '.data[] | [.released_at, .code, .name ] | @tsv'); then
30803113
return 2
30813114
fi
3082-
cz -d $'\t' -f 1 -i <(sort -u <<< "${sets[@]}")
3115+
cz -d $'\t' -e 'xdg-open https://scryfall.com/sets/{1}' -f 1 -i <(sort -u <<< "${sets[@]}")
30833116
}
30843117
30853118
cz_mtg_card() {
@@ -3089,16 +3122,16 @@ Select an MTG card by name using data from scryfall.com.
30893122
EOF
30903123
req curl sort || return 5
30913124
local url=""
3092-
if ! url=$(hold -pe -n scryfallbulk -t 86400 -- curl -sS https://api.scryfall.com/bulk-data \
3125+
if ! url=$(hold -pe -n scryfallbulk -t 604800 -- curl -sS https://api.scryfall.com/bulk-data \
30933126
| jq -r '.data[] | select(.type == "oracle_cards") | .download_uri'); then
30943127
return 2
30953128
fi
30963129
local data="" menu=""
3097-
if ! data=$(hold -e -n scryfalldata -t $((86400 * 7)) curl -sS "$url"); then
3130+
if ! data=$(hold -e -n scryfalldata -t 604800 -- curl -sS "$url"); then
30983131
return 2
30993132
fi
31003133
local filter='.[] | [.set, (.scryfall_uri | split("?"))[0], .name] | @tsv'
3101-
if ! menu=$(hold -g -t 43200 || hold -f <(jq -r "$filter" "$data" | sort -u)); then
3134+
if ! menu=$(hold -g -t 3600 || hold -f <(jq -r "$filter" "$data" | sort -u)); then
31023135
return 2
31033136
fi
31043137
cz -d $'\t' -e 'xdg-open {1}' -f 2 -i "$menu"
@@ -3453,7 +3486,6 @@ EOF
34533486
done
34543487
unset t c
34553488
3456-
34573489
cz_systemd_file() {
34583490
{ hep "$_CZ_HELP" && return; } <<EOF
34593491
cz systemd file [user|system] [TYPE]
@@ -3672,7 +3704,7 @@ EOF
36723704
use strict;
36733705
use warnings;
36743706
use open ":std", ":encoding(UTF-8)";
3675-
use Unicode::UCD qw/charinfo charscript charscripts charblock charblocks/;
3707+
use Unicode::UCD qw/charinfo charscript charscripts charblock charblocks/;
36763708
my (\$blocks,\$scripts) = (charblocks(),charscripts());
36773709
for (@ARGV) {
36783710
my \$section = \$blocks->{\$_} || \$scripts->{\$_};

www/index.org

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ cz [OPTIONS] [PLUGIN...] [ARGS ...] [< LINES]
6262
Select a line using your preferred interactive line selection tool.
6363

6464
OPTIONS
65-
These options print some information and exit:
65+
These options print some information then exit:
6666
-h : help : Show this help text or help text for plugin.
6767
-H : example : List example commands.
6868
-k : tools : List supported line selection tools.
@@ -89,19 +89,23 @@ OPTIONS
8989
-0 : Read null terminated lines from input.
9090
-i IN-FILE : Set file from which to read selections instead of stdin.
9191

92-
These options control which line selection utility is used:
92+
These options control how lines are selected:
93+
-w : Pick a line at random.
9394
-x : Use a graphical line selection tool.
9495
-y : Use a terminal line selection tool.
9596
-z TOOL : Use the given line selection tool.
9697

98+
These options control debugging features:
99+
-m : Print some debygging information.
100+
97101
TOOLS
98102
The following interactive line selection tools are supported:
99103
choose, dmenu, fzf, fzy, iselect, pick, pipedial, rofi, selecta, sentaku,
100104
slmenu, vis-menu, and zenity.
101105

102106
PLUGINS
103107
Plugins use cz for an application specific task. Each plugin defines input
104-
lines and options like the delimiter and templates.
108+
lines, delimiter, and template options.
105109
Run 'cz -l' to list plugins and 'cz -h PLUGIN' or 'cz help' for help text.
106110
All commands starting with 'cz_' are considered plugins.
107111

0 commit comments

Comments
 (0)