zsh-users
 help / color / mirror / code / Atom feed
* Disable most shell expansion to function or script
@ 2024-01-04 18:09 Sam B.
  2024-01-04 18:55 ` Stephane Chazelas
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Sam B. @ 2024-01-04 18:09 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 790 bytes --]

Hello,

I'm looking for a way to disable most shell expansion for the arguments 
to a script or function and treat everything up to a newline char as 
verbatim text, i.e. as if quoted.

For example, given a function/script "todo", I'd like

     todo Text inc. $var, *glob?, events!, <redirs, >(sub) & more

to behave more like it was quoted:

     todo 'Text inc. $var, *glob?, events!, <redirs, >(sub) & more'

I know of noglob to disable glob chars, and can have a look at histchars 
to see if events can be disabled. But I'm not sure if any of the other 
expansion can possibly disabled.

Mostly I'm interested joting down some plain text which could include 
'?!&' and have "todo" receive it all without the shell having done some 
magic beforehand.

Any ideas?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Disable most shell expansion to function or script
  2024-01-04 18:09 Disable most shell expansion to function or script Sam B.
@ 2024-01-04 18:55 ` Stephane Chazelas
  2024-01-04 19:16 ` Mikael Magnusson
  2024-01-04 23:38 ` Bart Schaefer
  2 siblings, 0 replies; 6+ messages in thread
From: Stephane Chazelas @ 2024-01-04 18:55 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1275 bytes --]

See
 https://unix.stackexchange.com/questions/714338/any-shell-where-expansions-are-turned-off-without-escaping-or-quoting

https://unix.stackexchange.com/questions/716836/zsh-alias-or-shell-function-to-only-echo-its-command-line-including-shell-cont

https://unix.stackexchange.com/questions/731845/how-to-write-a-function-that-takes-an-argument-string-that-does-not-need-to-be-q

For some possible avenues.


On 4 January 2024 18:09:57 GMT, "Sam B." <me@rmz.io> wrote:
>Hello,
>
>I'm looking for a way to disable most shell expansion for the arguments to a script or function and treat everything up to a newline char as verbatim text, i.e. as if quoted.
>
>For example, given a function/script "todo", I'd like
>
>    todo Text inc. $var, *glob?, events!, <redirs, >(sub) & more
>
>to behave more like it was quoted:
>
>    todo 'Text inc. $var, *glob?, events!, <redirs, >(sub) & more'
>
>I know of noglob to disable glob chars, and can have a look at histchars to see if events can be disabled. But I'm not sure if any of the other expansion can possibly disabled.
>
>Mostly I'm interested joting down some plain text which could include '?!&' and have "todo" receive it all without the shell having done some magic beforehand.
>
>Any ideas?

[-- Attachment #2: Type: text/html, Size: 2062 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Disable most shell expansion to function or script
  2024-01-04 18:09 Disable most shell expansion to function or script Sam B.
  2024-01-04 18:55 ` Stephane Chazelas
@ 2024-01-04 19:16 ` Mikael Magnusson
  2024-01-04 23:38 ` Bart Schaefer
  2 siblings, 0 replies; 6+ messages in thread
From: Mikael Magnusson @ 2024-01-04 19:16 UTC (permalink / raw)
  To: zsh-users; +Cc: Sam B.

On 1/4/24, Sam B. <me@rmz.io> wrote:
> Hello,
>
> I'm looking for a way to disable most shell expansion for the arguments
> to a script or function and treat everything up to a newline char as
> verbatim text, i.e. as if quoted.
>
> For example, given a function/script "todo", I'd like
>
>      todo Text inc. $var, *glob?, events!, <redirs, >(sub) & more
>
> to behave more like it was quoted:
>
>      todo 'Text inc. $var, *glob?, events!, <redirs, >(sub) & more'
>
> I know of noglob to disable glob chars, and can have a look at histchars
> to see if events can be disabled. But I'm not sure if any of the other
> expansion can possibly disabled.
>
> Mostly I'm interested joting down some plain text which could include
> '?!&' and have "todo" receive it all without the shell having done some
> magic beforehand.
>
> Any ideas?

function _accept_line () {
  if [[ $CONTEXT = vared ]] || [[ $zsh_eval_context != shfunc ]]; then
    zle .$WIDGET
    return
  fi
  if [[ "$BUFFER" = todo\ * ]]; then
    BUFFER="todo ${(q)BUFFER[6,-1]}"
    zle .$WIDGET
    return # not needed in this example but if you handle other stuff below
  fi
}

zle -N accept-line _accept_line
zle -N accept-line-and-down-history _accept_line
zle -N accept-and-hold _accept_line

Note that the quoted version will be saved in the history, and if you
recall the event, it will be quoted again by the above code, so there
is room for improvement / other ideas.

For example, make a function that takes no arguments, reads a single
line, and runs todo $REPLY for you. (todo itself could handle this if
given no arguments too?)

runquoted() {
  local cmd=( ${@:-todo} ) REPLY
  IFS= read -r
  $cmd $REPLY
}

% runquoted print -rl
asoeu a-;ua;,. ua-h,.uch <- my input
asoeu a-;ua;,. ua-h,.uch
% runquoted
aosot
zsh: command not found: todo

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Disable most shell expansion to function or script
  2024-01-04 18:09 Disable most shell expansion to function or script Sam B.
  2024-01-04 18:55 ` Stephane Chazelas
  2024-01-04 19:16 ` Mikael Magnusson
@ 2024-01-04 23:38 ` Bart Schaefer
  2024-01-05 17:53   ` Sam B.
  2 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2024-01-04 23:38 UTC (permalink / raw)
  To: zsh-users

On Thu, Jan 4, 2024 at 10:10 AM Sam B. <me@rmz.io> wrote:
>
> I'm looking for a way to disable most shell expansion for the arguments
> to a script or function

>      todo Text inc. $var, *glob?, events!, <redirs, >(sub) & more

accept-and-do-nothing() {
  BUFFER=': !#:0:s/\://:p !"'"$BUFFER"
  zle accept-line
}
zle -N accept-and-do-nothing

It's really difficult to avoid having the history references get
backslash-quoted ( in this example !, becomes \!, ), but otherwise
this skips everything.

What this does is:
- insert a : command as the word in command position.
- insert a history substitution that replaces that word with nothing
and then reprints the whole command without executing it
  (substitution is to avoid doubling the first word when !#:0 is reprinted)
- insert the !" reference that disables history for the remainder of
the command line
- accept the result to add the whole thing to the history list

If "todo" is the only command for which you want this effect, you
could replace the ":" with "todo".

> Mostly I'm interested joting down some plain text which could include
> '?!&' and have "todo" receive it all without the shell having done some
> magic beforehand.

The foregoing could be augmented with a zshaddhistory hook to
recognize the magic first word and dump the rest of the line into a
file.  Then
  todo $(<thatfile)
would pass the whole thing unmodified into "todo" which would have to
"eval" it or something.

However, have you considered using edit-command-line (possibly
repeatedly) to jot things down, and then quote-region or similar when
happy before executing?


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Disable most shell expansion to function or script
  2024-01-04 23:38 ` Bart Schaefer
@ 2024-01-05 17:53   ` Sam B.
  2024-01-14 23:28     ` Sam B.
  0 siblings, 1 reply; 6+ messages in thread
From: Sam B. @ 2024-01-05 17:53 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1737 bytes --]

On Jan 04, 2024 at 15:38, Bart Schaefer wrote:
> On Thu, Jan 4, 2024 at 10:10 AM Sam B. <me@rmz.io> wrote:
>> 
>> I'm looking for a way to disable most shell expansion for the arguments
>> to a script or function
> 
>>      todo Text inc. $var, *glob?, events!, <redirs, > (sub) & more
> 
> accept-and-do-nothing() {
>  BUFFER=': !#:0:s/\://:p !"'"$BUFFER"
>  zle accept-line
> }
> zle -N accept-and-do-nothing

That looks promising. Thanks.

> If "todo" is the only command for which you want this effect, you
> could replace the ":" with "todo".

Might want a few more. But this should only apply to these selected 
commands.

>> Mostly I'm interested joting down some plain text which could include
>> '?!&' and have "todo" receive it all without the shell having done some
>> magic beforehand.
> 
> However, have you considered using edit-command-line (possibly
> repeatedly) to jot things down, and then quote-region or similar when
> happy before executing?

I want this to be as frictionless and quick as possible. Opening up an 
editor is a bit much.

This made me realise though that I don't *need* it to be quoted, I would 
be happy if it would escape those chars individually, either as I type 
or on accepting the line.

I found this very similar question[1] from a few years ago which solves 
the problem for quotes. I'll also try this and see if it'll work for 
other special chars too.

[1]: https://www.zsh.org/mla/users/2021/msg00819.html

Will have a play with all this when back from holiday though. Silly of 
me to ask a question just before being AFK for a few weeks.

I'll have a read through `url-quote-magic` too, which seems to do 
something similar.

Thanks.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Disable most shell expansion to function or script
  2024-01-05 17:53   ` Sam B.
@ 2024-01-14 23:28     ` Sam B.
  0 siblings, 0 replies; 6+ messages in thread
From: Sam B. @ 2024-01-14 23:28 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1738 bytes --]

On Jan 05, 2024 at 17:53, Sam B. wrote:
> I'll have a read through `url-quote-magic` too, which seems to do 
> something similar.

I quite liked the behaviour of `url-quote-magic` to simply type any of 
the "special" chars and have them automatically quoted. So I've modified 
`url-quote-magic` to escape chars only when the first word matches 
`task` or any alias to it.

There's probably a few improvements possible, but here's a first pass of 
my solution.

zstyle -m ':task-quote-magic:\*' task-seps '*' ||
     zstyle -e ':task-quote-magic:*' task-seps 'reply=("#{}&<>''${histchars[1]}")'

zstyle -m ':task-quote-magic' task-cmds '*' ||
     zstyle -e ':task-quote-magic' task-cmds \
         'zmodload -i zsh/parameter;
          reply=( task
                  ${(k)galiases[(R)(* |)task *]:-}
                  ${(k)aliases[(R)(* |)task *]:-} )'

function task-quote-magic {
     setopt localoptions noksharrays extendedglob
     local qkey="${(q)KEYS}"
     local -a reply match mbegin mend
     # is key different than quoted key
     if [[ "$KEYS" != "$qkey" ]]
     then
         local lbuf="$LBUFFER$qkey"
         if [[ "${(Q)LBUFFER}$KEYS" == "${(Q)lbuf}" ]]
         then
             local -a words
             words=("${(@Q)${(z)lbuf}}")
             local taskseps taskcmds
             zstyle -s ":task-quote-magic" task-cmds taskcmds '|'
             if [[ "$words[1]" == (#b)${~taskcmds} ]]
             then
                 zstyle -s ":task-quote-magic:$match[1]" task-seps taskseps ''
             fi
             [[ "$taskseps" == *"$KEYS"* ]] &&
                 LBUFFER="$LBUFFER\\"
         fi
     fi
     zle .self-insert
}
zle -N self-insert task-quote-magic

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-01-14 23:30 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-04 18:09 Disable most shell expansion to function or script Sam B.
2024-01-04 18:55 ` Stephane Chazelas
2024-01-04 19:16 ` Mikael Magnusson
2024-01-04 23:38 ` Bart Schaefer
2024-01-05 17:53   ` Sam B.
2024-01-14 23:28     ` Sam B.

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).