Skip to content

Commit 2663690

Browse files
committed
new file: .gitignore
new file: .pre-commit-config.yaml new file: .zunit.yml new file: @str-dump new file: @str-ng-match new file: @str-ng-matches new file: @str-parse-json new file: @str-read-all new file: @str-read-ini new file: @str-read-toml new file: LICENSE new file: Makefile new file: README.md new file: tests/_output/.gitkeep new file: tests/_support/.gitkeep new file: tests/_support/bootstrap new file: tests/main.zunit new file: zsh-string-lib.lib.zsh
0 parents  commit 2663690

18 files changed

+949
-0
lines changed

.gitignore

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Zsh compiled script + zrecompile backup
2+
*.zwc
3+
*.zwc.old
4+
5+
# Zsh completion-optimization dumpfile
6+
*zcompdump*
7+
8+
# Zsh zcalc history
9+
.zcalc_history
10+
11+
# A popular plugin manager's files
12+
._zplugin
13+
.zplugin_lstupd
14+
15+
# zdharma/zshelldoc tool's files
16+
zsdoc/data
17+
18+
# robbyrussell/oh-my-zsh/plugins/per-directory-history plugin's files
19+
# (when set-up to store the history in the local directory)
20+
.directory_history
21+
22+
# MichaelAquilina/zsh-autoswitch-virtualenv plugin's files
23+
# (for Zsh plugins using Python)
24+
.venv
25+
26+
# Zunit tests' output
27+
/tests/_output/*
28+
!/tests/_output/.gitkeep

.pre-commit-config.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# See https://pre-commit.com for more information
2+
# See https://pre-commit.com/hooks.html for more hooks
3+
repos:
4+
- repo: https://github.com/pre-commit/pre-commit-hooks
5+
rev: v4.0.1
6+
hooks:
7+
- id: trailing-whitespace
8+
- id: end-of-file-fixer
9+
- id: check-yaml
10+
- id: check-added-large-files
11+
- repo: https://github.com/thlorenz/doctoc
12+
rev: v2.1.0
13+
hooks:
14+
- id: doctoc

.zunit.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tap: false
2+
directories:
3+
tests: tests
4+
output: tests/_output
5+
support: tests/_support
6+
time_limit: 0
7+
fail_fast: false
8+
allow_risky: false

@str-dump

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# -*- mode: sh; sh-indentation: 4; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
2+
# Copyright (c) 2018 Sebastian Gniazdowski
3+
#
4+
# @str-dump
5+
#
6+
# $1 - name of the variable of which contents should be dumped
7+
#
8+
# Dumps the contents of the variable, whether it's being a scalar,
9+
# an array or a hash. The contents of the hash are sorted on the
10+
# keys numerically, i.e.: by using `(on)` flags.
11+
#
12+
# An option -q can be provided: it'll enable quoting of the printed
13+
# data with the q-flag (i.e.: backslash quoting).
14+
#
15+
# Example:
16+
# array=( "" "a value" "test" )
17+
# @str-dump array
18+
#
19+
# Output:
20+
# ''
21+
# a\ value
22+
# test
23+
#
24+
# typeset -A hash=( "a key" "a value" key value )
25+
# @str-dump -q hash
26+
#
27+
# Output:
28+
# a\ key: a\ value
29+
# key: value
30+
31+
@str-dump() {
32+
if [[ $1 = -q ]] {
33+
integer quote=1
34+
shift
35+
} else {
36+
integer quote=0
37+
}
38+
39+
if [[ $1 = -- ]] { shift; }
40+
41+
local __var_name="$1"
42+
43+
(( ${(P)+__var_name} )) || {
44+
print "Error: the parameter \`$__var_name' doesn't exist"
45+
return 1
46+
}
47+
case ${(Pt)__var_name} in
48+
(*array*)
49+
(( quote )) && \
50+
{ print -rl -- "${(@qP)__var_name}"; ((1)); } || \
51+
print -rl -- "${(@P)__var_name}"
52+
;;
53+
(*association*)
54+
# The double kv usage is because the behavior
55+
# changed in a Zsh version
56+
local -a keys
57+
local key access_string
58+
keys=( "${(@kon)${(@Pk)__var_name}}" )
59+
for key in "${keys[@]}"; do
60+
access_string="${__var_name}[$key]"
61+
(( quote )) && \
62+
{ print -r -- "${(q)key}: ${(qP)access_string}"; ((1)); } || \
63+
print -r -- "$key: ${(P)access_string}"
64+
done
65+
;;
66+
(*)
67+
(( quote )) && \
68+
{ print -r -- "${(qP)__var_name}"; ((1)); } || \
69+
print -r -- "${(P)__var_name}"
70+
;;
71+
esac
72+
73+
return 0
74+
}
75+
76+
# vim:ft=zsh:sw=4:sts=4:et

@str-ng-match

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# -*- mode: sh; sh-indentation: 4; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
2+
# Copyright (c) 2018 Sebastian Gniazdowski
3+
#
4+
# @str-ng-match
5+
#
6+
# Returns a non-greedy match of the given pattern ($2)
7+
# in the given string ($1).
8+
#
9+
# $1 - the string to match in
10+
# $2 - the pattern to match in the string
11+
#
12+
# Example:
13+
#
14+
# if @str-ng-match "abb" "a*b"; then
15+
# print $REPLY
16+
# fi
17+
# Output: ab
18+
@str-ng-match() {
19+
local str="$1" pat="$2" retval=1
20+
: ${(S)str/(#b)(${~pat})/${retval::=0}}
21+
REPLY="${match[1]}"
22+
return "$retval"
23+
}
24+
25+
# vim:ft=zsh:sw=4:sts=4:et

@str-ng-matches

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# -*- mode: sh; sh-indentation: 4; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
2+
# Copyright (c) 2018 Sebastian Gniazdowski
3+
#
4+
# @str-ng-matches
5+
#
6+
# Returns all non-greedy matches of the given pattern ($2)
7+
# in the given string ($1).
8+
#
9+
# $1 … n-1 - the strings to match in
10+
# $n - the pattern to match in the strings
11+
#
12+
# Return value: $reply – contains all the matches
13+
# $REPLY - holds the first match
14+
# $?: 0 if there was any match found, otherwise 1
15+
#
16+
# Example:
17+
# arr=( a1xx ayy a2xx )
18+
# if @str-ng-matches ${arr[@]} "a*x"; then
19+
# print -rl $reply
20+
# fi
21+
#
22+
# Output:
23+
# a1x
24+
# a2x
25+
26+
@str-ng-matches() {
27+
local pat="${@[${#}]}" retval=1
28+
local -a input
29+
input=( "${@[1,${#}-1]}" ) reply=() match=()
30+
: "${(S)input[@]//(#b)(${~pat})/${reply[${#reply}+1]::=${match[1]}}${retval::=0}}"
31+
REPLY="${match[1]}"
32+
return $retval
33+
}
34+
35+
# vim:ft=zsh:sw=4:sts=4:et

@str-parse-json

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# -*- mode: sh; sh-indentation: 4; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
2+
# @str-parse-json
3+
#
4+
# Parses the buffer ($1) with JSON and returns:
5+
#
6+
# 1. Fields for the given key ($2) in the given hash ($3)
7+
# 2. The hash looks like follows:
8+
# 1/1 → strings at the level 1 of the 1st object
9+
# 1/2 → strings at the level 1 of the 2nd object
10+
#
11+
# 2/1 → strings at 2nd level of the 1st object
12+
#
13+
#
14+
# The strings are parseable with "${(@Q)${(@z)value}", i.e.:
15+
# they're concatenated and quoted strings found in the JSON.
16+
#
17+
# Example:
18+
#
19+
# {"zplugin-ices":{
20+
# "default":{
21+
# "wait":"1",
22+
# "lucid":"",
23+
# "as":"program",
24+
# "pick":"fzy",
25+
# "make":"",
26+
# },
27+
# "bgn":{
28+
# "wait":"1",
29+
# "lucid":"",
30+
# "as":"null",
31+
# "make":"",
32+
# "sbin":"fzy;contrib/fzy-*"
33+
# }
34+
# }}
35+
#
36+
# Will result in:
37+
#
38+
# local -A Strings
39+
# Strings[1/1]='zplugin-ices'
40+
# Strings[2/1]='default bgn'
41+
# Strings[3/1]='wait 1 lucid \ as program pick fzy make \ '
42+
# Strings[3/2]='wait 1 lucid \ as null make \ sbin fzy\;contrib/fzy-\*'
43+
#
44+
# So that when you e.g.: expect a key `bgn' but don't know at which
45+
# position, you can do:
46+
#
47+
# local -A Strings
48+
# @str-parse-json "$json" "zplugin-ices" Strings
49+
#
50+
# integer pos
51+
# pos=${${(@Q)${(@z)Strings[2/1]}}[(I)bgn]}
52+
# if (( pos )) {
53+
# local -A ices
54+
# ices=( "${(@Q)${(@z)Strings[3/$pos]}}" )
55+
# # Use the `ices' hash holding the values of the `bgn' object
56+
#
57+
# }
58+
#
59+
# $1 - the buffer with JSON
60+
# $2 - the key in the JSON that should be mapped to the
61+
# result (i.e.: you can map subset of the input)
62+
# $3 - the name of the output hash parameter
63+
64+
@str-parse-json() {
65+
emulate -LR zsh -o extendedglob -o warncreateglobal -o typesetsilent
66+
67+
local -A __pos_to_level __level_to_pos __pair_map \
68+
__final_pairs __Strings __Counts
69+
local __input=$1 __workbuf=$1 __key=$2 __varname=$3 \
70+
__style __quoting
71+
integer __nest=${4:-1} __idx=0 __pair_idx __level=0 \
72+
__start __end __sidx=1 __had_quoted_value=0
73+
local -a match mbegin mend __pair_order
74+
75+
(( ${(P)+__varname} )) || typeset -gA "$__varname"
76+
77+
__pair_map=( "(" ")" "{" "}" "[" "]" )
78+
while [[ $__workbuf = (#b)[^"{}()[]\\\"'":,]#((["({[]})\"'":,])|[\\](*))(*) ]]; do
79+
[[ -n ${match[3]} ]] && {
80+
__idx+=${mbegin[1]}
81+
82+
[[ $__quoting = \' ]] && \
83+
{ __workbuf=${match[3]}; } || \
84+
{ __workbuf=${match[3]:1}; (( ++ __idx )); }
85+
86+
} || {
87+
__idx+=${mbegin[1]}
88+
[[ -z $__quoting ]] && {
89+
if [[ ${match[1]} = ["({["] ]]; then
90+
__Strings[$__level/${__Counts[$__level]}]+=" $'\0'--object--$'\0'"
91+
__pos_to_level[$__idx]=$(( ++ __level ))
92+
__level_to_pos[$__level]=$__idx
93+
(( __Counts[$__level] += 1 ))
94+
__sidx=__idx+1
95+
__had_quoted_value=0
96+
elif [[ ${match[1]} = ["]})"] ]]; then
97+
(( !__had_quoted_value )) && \
98+
__Strings[$__level/${__Counts[$__level]}]+=" ${(q)__input[__sidx,__idx-1]//((#s)[[:blank:]]##|([[:blank:]]##(#e)))}"
99+
__had_quoted_value=1
100+
if (( __level > 0 )); then
101+
__pair_idx=${__level_to_pos[$__level]}
102+
__pos_to_level[$__idx]=$(( __level -- ))
103+
[[ ${__pair_map[${__input[__pair_idx]}]} = ${__input[__idx]} ]] && {
104+
__final_pairs[$__idx]=$__pair_idx
105+
__final_pairs[$__pair_idx]=$__idx
106+
__pair_order+=( $__idx )
107+
}
108+
else
109+
__pos_to_level[$__idx]=-1
110+
fi
111+
fi
112+
}
113+
114+
[[ ${match[1]} = \" && $__quoting != \' ]] && \
115+
if [[ $__quoting = '"' ]]; then
116+
__Strings[$__level/${__Counts[$__level]}]+=" ${(q)__input[__sidx,__idx-1]}"
117+
__quoting=""
118+
else
119+
__had_quoted_value=1
120+
__sidx=__idx+1
121+
__quoting='"'
122+
fi
123+
124+
[[ ${match[1]} = , && -z $__quoting ]] && \
125+
{
126+
(( !__had_quoted_value )) && \
127+
__Strings[$__level/${__Counts[$__level]}]+=" ${(q)__input[__sidx,__idx-1]//((#s)[[:blank:]]##|([[:blank:]]##(#e)))}"
128+
__sidx=__idx+1
129+
__had_quoted_value=0
130+
}
131+
132+
[[ ${match[1]} = : && -z $__quoting ]] && \
133+
{
134+
__had_quoted_value=0
135+
__sidx=__idx+1
136+
}
137+
138+
[[ ${match[1]} = \' && $__quoting != \" ]] && \
139+
if [[ $__quoting = "'" ]]; then
140+
__Strings[$__level/${__Counts[$__level]}]+=" ${(q)__input[__sidx,__idx-1]}"
141+
__quoting=""
142+
else
143+
__had_quoted_value=1
144+
__sidx=__idx+1
145+
__quoting="'"
146+
fi
147+
148+
__workbuf=${match[4]}
149+
}
150+
done
151+
152+
local __text value __found
153+
integer __pair_a __pair_b
154+
for __pair_a ( "${__pair_order[@]}" ) {
155+
__pair_b="${__final_pairs[$__pair_a]}"
156+
__text="${__input[__pair_b,__pair_a]}"
157+
if [[ $__text = [[:space:]]#\{[[:space:]]#[\"\']${__key}[\"\']* ]]; then
158+
if (( __nest != 2 )) {
159+
__found="$__text"
160+
break
161+
}
162+
fi
163+
}
164+
165+
if [[ -n $__found && $__nest -lt 2 ]] {
166+
@str-parse-json "$__found" "$__key" "$__varname" 2
167+
}
168+
169+
if (( __nest == 2 )) {
170+
: ${(PAA)__varname::="${(kv)__Strings[@]}"}
171+
}
172+
}
173+
174+
# vim:ft=zsh:sts=4:sw=4:et

0 commit comments

Comments
 (0)