zsh-workers
 help / color / mirror / code / Atom feed
From: Daniel Shahaf <d.s@daniel.shahaf.name>
To: zsh-workers@zsh.org
Subject: Re: Unset “zle_bracketed_paste” .zshrc
Date: Sat, 14 Mar 2020 03:28:45 +0000	[thread overview]
Message-ID: <20200314032845.2b2930e5@tarpaulin.shahaf.local2> (raw)
In-Reply-To: <1580998165.14726.20.camel@samsung.com>

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

Peter Stephenson wrote on Thu, 06 Feb 2020 14:09 +0000:
> On Thu, 2020-02-06 at 14:32 +0100, Mikael Magnusson wrote:
> > On 2/6/20, Daniel Shahaf <d.s@daniel.shahaf.name> wrote:  
> > > 
> > > Well, it's an option.  It would result in the following interface:
> > > to prevent $zle_bracketed_paste from being defined one will have to run
> > > «unset zle_bracketed_paste» if zsh/zle has been loaded, or «zmodload -Fa
> > > zsh/zle -p:zle_bracketed_paste» otherwise.  
> > I would assume that if someone knew to run that obscure zmodload
> > command, they would know they could just do this instead,
> > zmodload zsh/zle
> > unset zle_bracketed_paste  
> 
> No, this is entirely about autoload behaviour.  "zmodload -Fa" provides
> selective autoload out of the box, which in principle fixes the issue
> with no fundamentally new features, just appropriate module exports.
> 
> However, the main reason for doing this with zmodload would be to
> provide consistency with different types of module feature, and there's
> no real call for that as people are much more used to the parameter
> interface.  So in practice adding behaviour to "unset" is probably
> easier for everyone.
> 

I've got a WIP patch for this that I'd like to share.  It fixes the
xfail ('f'-status) test; however, I'm not sure everything in it's
correct, and there are a few outstanding todo's.  It's nowhere near
being ready to be committed; I'm only posting it now for 'release early
and often' reasons.

It's attached.

Cheers,

Daniel

> It would be neater to be more consistent about the way module features
> are provided, just on the basis that if it's in a module it should use
> the module interface, else why are we pretending it's a module at all
> rather than building it into the shell?  But that can go way down a very
> long list.
> 
> pws
> 


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 6328 bytes --]

diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index ef9148d7b..43265f676 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -1114,7 +1114,8 @@ scanpmmodules(UNUSED(HashTable ht), ScanFunc func, int flags)
 	}
     for (i = 0; i < realparamtab->hsize; i++)
 	for (hn = realparamtab->nodes[i]; hn; hn = hn->next) {
-	    if ((((Param) hn)->node.flags & PM_AUTOLOAD) &&
+	    int flags = ((Param) hn)->node.flags;
+	    if ((flags & PM_AUTOLOAD) && !(flags & PM_UNSET) &&
 		!linknodebystring(done, ((Param) hn)->u.str)) {
 		pm.node.nam = ((Param) hn)->u.str;
 		addlinknode(done, pm.node.nam);
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 8c0534708..6c88a9157 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -2239,6 +2239,8 @@ setup_(UNUSED(Module m))
     bpaste[0] = ztrdup("\033[?2004h");
     bpaste[1] = ztrdup("\033[?2004l");
     /* Intended to be global, no WARNCREATEGLOBAL check. */
+    /* ### TODO: Don't set it if it's already set */
+    /* ### TODO: Make it a module parameter to let it be preemptively unset in zshrc */
     assignaparam("zle_bracketed_paste", bpaste, 0);
 
     return 0;
diff --git a/Src/module.c b/Src/module.c
index f41b82f25..7ac93ee4b 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -1018,6 +1018,7 @@ runhookdef(Hookdef h, void *d)
  * requires that either there's no parameter already present,
  * or it's a global parameter marked for autoloading.
  *
+ * Return status is zero on success, non-zero on failure.
  * The special status 2 is to indicate it didn't work but
  * -i was in use so we didn't print a warning.
  */
@@ -1030,7 +1031,8 @@ checkaddparam(const char *nam, int opt_i)
     if (!(pm = (Param) gethashnode2(paramtab, nam)))
 	return 0;
 
-    if (pm->level || !(pm->node.flags & PM_AUTOLOAD)) {
+    if (pm->level
+	    || (pm->node.flags & (PM_AUTOLOAD|PM_UNSET)) != PM_AUTOLOAD) {
 	/*
 	 * -i suppresses "it's already that way" warnings,
 	 * but not "this can't possibly work" warnings, so we print
@@ -1056,12 +1058,20 @@ checkaddparam(const char *nam, int opt_i)
 /* This adds the given parameter definition. The return value is zero on *
  * success and 1 on failure. */
 
-/**/
-int
+static int
 addparamdef(Paramdef d)
 {
     Param pm;
 
+    /* If there's already a "tombstone", honour it and don't add the parameter. */
+    /* ### TODO: verify that a tombstone can be removed by the user if desired */
+    {
+	Param pm2 = (Param) gethashnode2(paramtab, d->name);
+	if (pm2 && pm2->node.flags & PM_AUTOLOAD && pm2->node.flags & PM_UNSET) {
+	    return 0;
+	}
+    }
+
     if (checkaddparam(d->name, 0))
 	return 1;
 
@@ -1199,6 +1209,16 @@ add_autoparam(const char *module, const char *pnam, int flags)
     Param pm;
     int ret;
 
+    /* If there's already a "tombstone" parameter, we simply need to
+     * revive it. */
+    {
+	Param pm2 = (Param) gethashnode2(paramtab, pnam);
+	if (pm2 && pm2->node.flags & PM_AUTOLOAD && pm2->node.flags & PM_UNSET) {
+	    pm2->node.flags &= ~PM_UNSET;
+	    return 0;
+	}
+    }
+
     queue_signals();
     if ((ret = checkaddparam(pnam, (flags & FEAT_IGNORE)))) {
 	unqueue_signals();
diff --git a/Src/params.c b/Src/params.c
index 863b32600..9d4548720 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -527,7 +527,7 @@ getparamnode(HashTable ht, const char *nam)
 	(void)ensurefeature(mn, "p:", (pm->node.flags & PM_AUTOALL) ? NULL :
 			    nam);
 	hn = gethashnode2(ht, nam);
-	if (!hn) {
+	if (!hn || (pm->node.flags & PM_UNSET)) {
 	    /*
 	     * This used to be a warning, but surely if we allow
 	     * stuff to go ahead with the autoload stub with
@@ -3604,6 +3604,7 @@ unsetparam_pm(Param pm, int altflag, int exp)
 {
     Param oldpm, altpm;
     char *altremove;
+    int node_removed = 0; /* boolean flag */
 
     if ((pm->node.flags & PM_READONLY) && pm->level <= locallevel) {
 	zerr("read-only variable: %s", pm->node.nam);
@@ -3670,8 +3671,21 @@ unsetparam_pm(Param pm, int altflag, int exp)
 	(pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL)
 	return 0;
 
-    /* remove parameter node from table */
-    paramtab->removenode(paramtab, pm->node.nam);
+    /* 
+     * Remove parameter node from table.
+     * 
+     * For autoloaded parameters, we leave the Param behind with
+     * the PM_UNSET flag on, as a "tombstone" so zmodload won't
+     * try to create this parameter later.  Cf. add_autoparam()
+     * and getparamnode().
+     */
+    if (pm->node.flags & PM_AUTOLOAD)
+	/* ### TODO: audit all uses of PM_AUTOLOAD to see if they need to handle tombstones */
+	pm->node.flags |= PM_UNSET;
+    else {
+	paramtab->removenode(paramtab, pm->node.nam);
+	node_removed = 1;
+    }
 
     if (pm->old) {
 	oldpm = pm->old;
@@ -3692,7 +3706,8 @@ unsetparam_pm(Param pm, int altflag, int exp)
 	}
     }
 
-    paramtab->freenode(&pm->node); /* free parameter node */
+    if (node_removed)
+	paramtab->freenode(&pm->node); /* free parameter node */
 
     return 0;
 }
diff --git a/Test/V01zmodload.ztst b/Test/V01zmodload.ztst
index 0a7fbb651..077a252dc 100644
--- a/Test/V01zmodload.ztst
+++ b/Test/V01zmodload.ztst
@@ -353,20 +353,19 @@
    if zmodload -e zsh/parameter; then zmodload -u zsh/parameter; fi
    unset options
    zmodload zsh/parameter
-   echo \$+options
+   echo \$+options +\$options+
  "
--f:can unset a non-readonly autoloadable parameter before loading the module
->0
-# Currently prints '1'.
+0:can unset a non-readonly autoloadable parameter before loading the module
+>0 ++
 
  $ZTST_testdir/../Src/zsh -fc "
    MODULE_PATH=${(q)MODULE_PATH}
    zmodload zsh/parameter
    unset options
-   echo \$+options
+   echo \$+options +\$options+
  "
 0:can unset a non-readonly autoloadable parameter after loading the module
->0
+>0 ++
 
  $ZTST_testdir/../Src/zsh -fc "
    MODULE_PATH=${(q)MODULE_PATH}
@@ -375,7 +374,10 @@
  "
 -f:can't unset a readonly autoloadable parameter before loading the module
 *?zsh:?: read-only variable: builtins
-# Currently, the 'unset' succeeds.
+# Currently, the 'unset' succeeds.  For it to fail, the code would need to
+# know that $builtins is read-only.  However, that information only becomes
+# available after features_() is called, which happens after loading the
+# module.
 
  $ZTST_testdir/../Src/zsh -fc "
    MODULE_PATH=${(q)MODULE_PATH}

  reply	other threads:[~2020-03-14  3:29 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-17 23:20 Andrew Reyes
2020-01-18 19:40 ` Daniel Shahaf
2020-01-23  3:12   ` Daniel Shahaf
2020-01-23  9:53     ` Peter Stephenson
2020-01-26  0:45       ` Daniel Shahaf
2020-01-27 14:01         ` Peter Stephenson
2020-01-28 11:09           ` Peter Stephenson
2020-01-29 11:23             ` Peter Stephenson
2020-02-06 12:40               ` Daniel Shahaf
2020-02-06 13:32                 ` Mikael Magnusson
2020-02-06 14:09                   ` Peter Stephenson
2020-03-14  3:28                     ` Daniel Shahaf [this message]
2020-01-29  8:34           ` Daniel Shahaf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200314032845.2b2930e5@tarpaulin.shahaf.local2 \
    --to=d.s@daniel.shahaf.name \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).