-
Notifications
You must be signed in to change notification settings - Fork 3
Home
It's a shame that even NixOS, a system with declarative configuration at its core, implements declaring of Bash and Zsh configuration by blocks of text assigned to some configuration fields. This isn't "declaring", it's a regular shell configuration maintenance.
The project and the language behind it – the ZQL – is to solve this problem. Basing on the parser that's built into Zsh and exposed via the (z)
flag it will allow to truly declare the contents of shell scripts, being the Bash (Zsh correctly parses a very large subset of Bash syntax) or Zsh startup files, or regular shell scripts.
Below is a draft version of the language. If you'll see any mistakes or inconstences then feel free to report them to r/zplugin subreddit.
- quoting-free symbols
-
#
,"#"
,'#'
,$'#'
all match any string, i.e.string
,"string"
,'string'
,$'string'
but not var -
$
,"$"
,'$'
,$'$'
all match any variable, in any quoting, i.e.$var
,"$var"
,'$var'
,$'$var'
-
*
,"*"
,'*'
,$'*'
all match anything, i.e. in practice any combination of string and var, in any quoting
-
- quoting-locked symbols
-
##
,"##"
,'##'
,$'##'
all match only the corresponding string, i.e.##
matchesstring
,"##"
matches"string"
, etc. -
$$
,"$$"
,'$$'
,$'$$'
all match only the corresponding quoting, i.e.$$
matches$var
,"$$"
matches"$var"
, etc. -
**
,"**"
,'**'
,$'**'
all match anything, i.e. in practice any combination of string and var, but only with concrete quoting that's being the same as the quoting of the symbol
-
- BEGIN – match the beginning of the script
- INSERT – insert the 2 commands
declzsh 'BEGIN INSERT { typeset -F4 SECONDS=0; bindkey ^T widget }'
-
BEGIN – match the beginning of the script
-
IFNE – if not exists – if there's no bindkey with arbitrary arguments (the
%
) at the beginning of the script, then -
INSERT – insert the bindkey command
declzsh 'BEGIN IFNE { bindkey % }
INSERT { bindkey ^T widget }'
- BEGIN[2] – match the second line of the script – IFE – if-exists – if it's a bindkey with 2 arbitrary strings (but not vars), then
- ALTER – set the second argument to
widget
leaving the first one unchanged
declzsh 'BEGIN[2] IFE { bindkey # # }
ALTER { bindkey * widget }'
- BEGIN[3] – match the third line of the script
- IFE – if-exists – if it's a bindkey with 2 arbitrary strings (but not vars), then
- BEGIN[4] – match the fourth line of the script
- ALTER – set the second argument to
widget
leaving the first one unchanged
declzsh 'BEGIN[3] IFE { bindkey # # }
BEGIN[4] ALTER { bindkey * widget }'
Base concept: if zplugin is sourced somewhere in the .zshrc
, then add a new plugin zdharma/null
after last loaded plugin.
- BODY – matches whole
.zshrc
- IFE – if-exists – checks whether the command
source ...
exists in the.zshrc
(i.e. in the matched portion of.zshrc
, by the preceding BODY directive) - PRE[-1] – moves the insert pointer after the command that matches (i.e. the
zplugin load %
); [-1] – take the last such matching command - INSERT – appends given command after the command matched by PRE
declzsh 'BODY IFE { source '%/zplugin.zsh' }
PRE[-1] { zplugin load % }
INSERT { zplugin load zdharma/null }'
- END – match the end of the script
- INSERT – append the
echo ...
command
declzsh 'END INSERT { echo "[zshrc] Load time:" $SECONDS sec }'
- END – match the end of the script
- IFNE – if there's no echo with substring
"[zshrc] "
in the first argument, then - INSERT – append the
echo ...
command
declzsh 'END IFNE { echo "[zshrc] %" % }
INSERT { echo "[zshrc] Load time:" $SECONDS sec }'
- END[-2] – match the second-line from the end of the script
- IFE – if there's echo with arbitrary string as 1st arg, an arbitrarily quoted var as the second arg, and then an arbitrary string as the third arg, then argument, then
- ALTER – set the echo to have only single argument the string inside single quoting
declzsh 'END[-2] IFE { echo # $ # }
ALTER { echo "[zshrc] Load time: $SECONDS sec" }'
- END[-3] – match the third-line from the end of the script
- IFE – if it's
SECONDS=0
, then - DELETE – delete it
declzsh 'END[-3] IFE { SECONDS=0 }
DELETE'
- END[-3] – match the third-line from the end of the script
- IFE – if it's
SECONDS=0
, then - DELETE – delete it and a following command and also any following blank line (because of the
+
)
declzsh 'END[-3] IFE { SECONDS=0 }
END[-2] DELETE %,+'
-
PRE – Grep through file searching for command
setopt
with any string (i.e.str
,'str'
,"str"
,$'str'
) but not var (for string AND var there's*
, for var-only there's$
) followed by any number of whitespace and then by command print that takes exactly"any-combination-of-string-and-var"
-
ALTER – for the command following the one matched with PRE, which should be
echo
set the second argument to "added" leaving the first one unchanged; then for any following command (e.g. make) set the second argument to DEBUG=1; then, set the argument of the following command, which should bels
, to*
-
POST – grep for an assignment
VALUE={any-string-or-var-with-any-quoting}
The PRE and POST are to match a specific part of the script, i.e. to provide a surrounding context for the inner matching that does the editing
declzsh 'PRE { setopt #; print "**"; }
ALTER { echo * "added"; * DEBUG=1; ls \* }
POST { VALUE=* }'
-
PRE – setopt with exactly
"string"
as an argument and a blank following line (because of the+
), then a print with exactly"string$var"
or"$var$var"
as the 1st arg and with exactlystring
or"anything"
as the second arg -
INSERT – appends 2 commands
ls *
(no quoting of*
needed, as this is an insert of a text, not e.g. an ALTER command) and theecho ...
and a blank line after the echo (because of the+
) -
POST – match for assignment
VALUE="anything-exactly-this-way-quoted"
declzsh 'PRE { setopt "##"+; print "##$|$+$" ##|"**" }
INSERT { ls *; echo "Hello World"+ }
POST { VALUE="**" }'
-
PRE – match a blank line then a setopt with
"anything"
as the arg and then a blank line, then a print with$var$var
or"$var$var"
etc. (quoting is arbitrary because the pattern isn't"$$+$$"
or at least"$$+$"
) as the first arg then the line-continuation backslash then an arbitrarily quoted arbitrary argument and then ANYTHING – the%
is like an "pass-through all", or "accept-all" or "match-anything" -
DELETE – delete any following command, then a blank line, then again any following command and then the echo with arbitrary arguments
declzsh 'PRE { +setopt "**"+; print "$+$" \\+"*" % }
DELETE { %;+;%;echo % }'