Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IDEA] The docs for :then and :else filter run prefixes should mention each other #8933

Open
rmunn opened this issue Feb 4, 2025 · 8 comments

Comments

@rmunn
Copy link
Contributor

rmunn commented Feb 4, 2025

I think the docs for the :then filter run prefix and the :else filter run prefix should mention each other. Just a "See also" at the end would be enough; if you're using :then then you probably want to know about :else, and vice versa. They're both accessible through clicking the "Named Filter Run Prefix" as well as through many other wikiwalking paths, but these seem like two documentation tiddlers that should really cross-link to each other.

Same with the then and else filter operators: their doc tiddlers should probably have "See also else" and so on.

Finally, while I'm at it, since :then mentions the then filter operator and then also mentions :then, it would be good for else and :else to mention each other as well.

I plan to submit a PR for this soon, though probably not today.

@yaisog
Copy link
Contributor

yaisog commented Feb 13, 2025

May I suggest extending this sentence in the :then docs

If the output of a :then prefixed filter run is itself an empty list, the result of all previous filter runs is passed through unaltered.

by this

This allows for chaining with the :else filter run prefix, because the input to :else will remain a non-empty list even if the :then filter run produces no results and therefore not cause the :else filter run to be erroneously evaluated.

in which you could link to the :else filter run prefix.

@pmario
Copy link
Member

pmario commented Feb 13, 2025

This allows for chaining with the :else filter run prefix, because the input to :else will remain a non-empty list even if the :then filter run produces no results and therefore not cause the :else filter run to be erroneously evaluated.

IMO this sentence is way to long. I did read it 3 times and I do not know what you try to say. May be split it into 3 sentences. -- Can you link to an example?

@yaisog
Copy link
Contributor

yaisog commented Feb 13, 2025

Feel free to improve on it.

What I am trying to say is that if

  • the run preceding :then[] and :else[] did produce a result and
  • :then[] (hypothetically) did return its empty result

then the :else[] filter run would then also be evaluated since its input would be the empty list output by :then. This is probably not what the user wants. By passing its own input in this case, the :then[] filter run prevents the :else[] filter run from being evaluated. This is usually the intended behavior since the preceding run did produce a result and therefore should not trigger the :else[].

I do not know how to make it clearer. If you routinely rely on it for conditional branching within filters you will quickly come to appreciate this behavior.

@pmario
Copy link
Member

pmario commented Feb 13, 2025

I do not know how to make it clearer. If you routinely rely on it for conditional branching within filters you will quickly come to appreciate this behavior.

I personally have no idea, what you mean. Do you have some examples. The filter syntax is very complex and processing it "by heart" without concrete examples is close to impossible. At least for me.

@yaisog
Copy link
Contributor

yaisog commented Feb 13, 2025

Here's an example of a typical usage pattern for me:

Suppose you have a checkbox that sets the tiddler $:/state/checkbox-state to either tagged or untagged.
Now you could do something like

<$list filter="[{$:/state/checkbox-state}match[tagged]] :then[all[tiddlers]!untagged[]] :else[all[tiddlers]untagged[]]" />

(This is just for illustration. There would probably be better ways to do this.)
If there were no tiddlers with tags, the :then filter run would have an empty result. If this were to be used as the input for the :else run, then that run would be evaluated, listing all untagged tiddlers even though we wanted to list the tagged ones. What actually happens in this case, though, is that then: passes its input along, which is tagged, so the :else run is not evaluated. Unfortunately for this example, this is also not quite what we need (i.e. zero-length list of tiddlers with tags), but at least it's not the opposite...

BTW, what I would really like to see is a suffix to :then like :then:blank which replaces any input with the empty list [[]] if the run result is empty. This empty list will also not trigger :else evaluation, but is easier to handle in further processing (e.g. [!is[blank]]). Currently, I usually use :then[‹some filters›else[]] for something equivalent, but it's ugly. Actually, no one needs the original input to :then at the filter output, ever, so this should have been default behavior without any suffix, but backwards compatibility is our most holy and cherished relic.

@yaisog
Copy link
Contributor

yaisog commented Feb 14, 2025

If someone ever stumbles upon this thread with the same problem, here is the a :then filter run prefix that returns a single blank item when the run produces no results and the suffix :blank is used:

/*\
title: $:/core/modules/filterrunprefixes/then.js
type: application/javascript
module-type: filterrunprefix

Replace results of previous runs
If empty, either return previous results or a single blank item when suffix "blank" is used

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

/*
Export our filter prefix function
*/
exports.then = function(operationSubFunction,options) {
	return function(results,source,widget) {
		if(results.length !== 0) {
			// Only run if previous run(s) produced results
			var thisRunResult = operationSubFunction(source,widget),
				suffixes = options.suffixes,
				blank = (suffixes[0] && suffixes[0][0] === "blank") ? true : false;
			if (thisRunResult.length !== 0) {
				// Replace results only if this run actually produces a result
				results.clear();
				results.pushTop(thisRunResult);
			} else if (blank) {
				// Ensure an empty string is returned if suffix "blank" is used
				results.clear();
				results.pushTop([""]);
			}
		}
	};
};

})();

Simply replace the contents of $:/core/modules/filterrunprefixes/then.js with the above.

@Jermolene
Copy link
Member

Hi @rmunn thank you, the improvements you suggest in the OP would be very helpful.

@pmario
Copy link
Member

pmario commented Feb 14, 2025

@rmunn ... I did create a PR #8949 please check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants