diff --git a/ChangeLog b/ChangeLog index ec1e413c7..1fd8b9944 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-05-02 Daniel Shahaf + * 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