about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDaniel Shahaf <d.s@daniel.shahaf.name>2020-04-29 00:30:17 +0000
committerDaniel Shahaf <d.s@daniel.shahaf.name>2020-05-02 01:12:07 +0000
commit34d69acbef44f654ea51d762ffdb02f5b1e8b9e1 (patch)
tree78812032a1ac8e24688ec93b3b1539ca257b69d2
parent95adde8ddc744af744975a58dccd2c3cc53b5333 (diff)
downloadzsh-34d69acbef44f654ea51d762ffdb02f5b1e8b9e1.tar.gz
zsh-34d69acbef44f654ea51d762ffdb02f5b1e8b9e1.tar.xz
zsh-34d69acbef44f654ea51d762ffdb02f5b1e8b9e1.zip
45737 (+ docs, and update the test from 45722): zstyle: When determining the weight (specificity) of a pattern, consider the number of components before anything else, as documented.
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/mod_zutil.yo6
-rw-r--r--README19
-rw-r--r--Src/Modules/zutil.c13
-rw-r--r--Test/V05styles.ztst2
5 files changed, 40 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index ec1e413c7..1fd8b9944 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2020-05-02  Daniel Shahaf  <d.s@daniel.shahaf.name>
 
+	* 45737 (+ docs, and update the test from 45722):
+	Doc/Zsh/mod_zutil.yo, README, Src/Modules/zutil.c,
+	Test/V05styles.ztst: zstyle: When determining the weight
+	(specificity) of a pattern, consider the number of components
+	before anything else, as documented.
+
 	* unposted: Test/V05styles.ztst: Revert unintentional move
 	from 45722.
 
diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo
index c69233f9d..9c50e6122 100644
--- a/Doc/Zsh/mod_zutil.yo
+++ b/Doc/Zsh/mod_zutil.yo
@@ -40,8 +40,8 @@ that it looks up the tt(preferred-precipitation) style under the
 `tt(:weather:)var(continent)tt(:)var(day-of-the-week)tt(:)var(phase-of-the-moon))' context.
 According to this, you might set the following in your tt(zshrc):
 
-example(zstyle ':weather:*:Sunday:*' preferred-precipitation snow
-zstyle ':weather:europe:*' preferred-precipitation rain)
+example(zstyle ':weather:europe:*' preferred-precipitation rain
+zstyle ':weather:*:Sunday:*' preferred-precipitation snow)
 
 Then the plugin would run under the hood a command such as
 
@@ -52,7 +52,7 @@ On Sundays tt($REPLY) would be set to `tt(snow)'; in Europe it would be set
 to `tt(rain)'; and on Sundays in Europe it would be set to `tt(snow)' again,
 because the patterns `tt(:weather:europe:*)' and `tt(:weather:*:Sunday:*)' both
 match the var(context) argument to tt(zstyle -s), are equally specific, and the
-latter was defined first.
+latter is more specific (because it has more colon-separated components).
 
 em(Usage)
 
diff --git a/README b/README
index b87f660bf..8ae615153 100644
--- a/README
+++ b/README
@@ -64,6 +64,25 @@ The sh-compatible function definition syntax, "f() { ... }", is unchanged.
 The time-out (-t) value given to zsh/system's `zsystem flock` command is
 now limited to 2^30-1 seconds (= a little over 34 years).
 
+zstyle: For background, recall that the zstyle builtin associates styles with
+values for particular contexts, and when a context (such as ':foo:bar:baz') is
+matched by multiple patterns (such as ':foo:*' and ':foo:bar:*'), the style's
+value for the more specific of the patterns is used.  In zsh 5.8 and earlier
+the determination of which pattern is "more specific" used semantics slightly
+different to those the documentation promised.  The implementation was changed
+to match the documentation.  The upshot of this is that if you set a single
+style in multiple contexts, zsh 5.9 may use the values set for a pattern other
+than the one zsh 5.8 used.  For example, if you do
+    zstyle ':foo:bar:*'   style value1
+    zstyle ':foo:*:baz:*' style value2
+and the style is looked up under a context that both patterns match (e.g.,
+:foo:bar:baz:qux), zsh 5.9 will use value2 -- which is consistent with the
+documentation of both 5.8 and 5.9 -- but zsh 5.8 will use value1.  If this
+affects you, make the implied colons in the first pattern explicit, as in:
+    zstyle ':foo:bar:*:*' style value1
+    zstyle ':foo:*:baz:*' style value2
+This will use value1 in both 5.8 and 5.9.
+
 Incompatibilities between 5.7.1 and 5.8
 ---------------------------------------
 
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index 7d9bf05d6..5c96d06c1 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -96,7 +96,7 @@ struct stypat {
     Stypat next;
     char *pat;			/* pattern string */
     Patprog prog;		/* compiled pattern */
-    int weight;			/* how specific is the pattern? */
+    zulong weight;		/* how specific is the pattern? */
     Eprog eval;			/* eval-on-retrieve? */
     char **vals;
 };
@@ -293,7 +293,9 @@ newzstyletable(int size, char const *name)
 static int
 setstypat(Style s, char *pat, Patprog prog, char **vals, int eval)
 {
-    int weight, tmp, first;
+    zulong weight;
+    int tmp;
+    int first;
     char *str;
     Stypat p, q, qq;
     Eprog eprog = NULL;
@@ -348,6 +350,12 @@ setstypat(Style s, char *pat, Patprog prog, char **vals, int eval)
      * - A component that's a literal string scores 2 points.
      * - The score of a pattern is the sum of the score of its components.
      *
+     * The result of this calculation is stored in the low bits of 'weight'.
+     * The high bits of 'weight' are used to store the number of ':'-separated
+     * components.  This provides a lexicographic comparison: first compare
+     * the number of components, and if that's equal, compare the specificity
+     * of the components.
+     *
      * This corresponds to the notion of 'more specific' in the zshmodules(1)
      * documentation of zstyle.
      */
@@ -367,6 +375,7 @@ setstypat(Style s, char *pat, Patprog prog, char **vals, int eval)
 
 	if (*str == ':') {
 	    /* Yet another component. */
+	    weight += ZLONG_CONST(1) << (CHAR_BIT * sizeof(weight) / 2);
 
 	    first = 1;
 	    weight += tmp;
diff --git a/Test/V05styles.ztst b/Test/V05styles.ztst
index 9b5fc4517..048751941 100644
--- a/Test/V05styles.ztst
+++ b/Test/V05styles.ztst
@@ -163,4 +163,4 @@
  )
 0:the example in the documentation remains correct
 >snow
->rain
+>snow