Clarification: How filter operator, :filter, and :map run prefixes work?

While there are good documentation on filter, :filter, and :map on tiddlywiki.com, still there are confusions in using them! I would appreciate if through more examples, application of these excellent tools clarified.

Conclusion

Based on @saqimtiaz clarification, I conclude the below discussion as:

  1. There are no requirements for :filter beyond that if it returns a result for an input title, that title is kept and if not, it is discarded.
  2. Similarly, the only requirement for :map is that it return a single result for every input title
  3. Filter run prefixes can accept filter constructors like :filter[all[tiddlers]....
  4. Filter run prefixes :filter, :map and :reduce only receive a single title as input. So if you want to query all tiddlers, you need to start your filter run with all[tiddlers].
  5. :filter is a filter run prefix. Filter run prefixes need the filter run to be provided as literal strings, you cannot use variables. If you want to use a variable, then use the filter[] operator.
2 Likes

Q1

Can I use filter or :filter like below? That means, can I use selection constructor inside theme?

<$vars  pf="UWXYZ">
<$list filter="[<pf>split[]] :filter[all[tiddlers]!is[system]prefix<currentTiddler>]">

</$list>
</$vars>

Also

<$vars  pf="UWXYZ" slflt="[all[tiddlers]!is[system]prefix{!!title}]">
<$list filter="[<pf>split[]filter<slflt>">

</$list>
</$vars>

In both cases above, a selection constructor is used inside filter and :filter. Are we allowed to use a selection constructor or we have to use selection modifier only?

@Mohammad I believe we have discussed :filter a few times now :slight_smile:

There are no requirements for :filter beyond that if it returns a result for an input title, that title is kept and if not, it is discarded.

Similarly, the only requirement for :map is that it return a single result for every input title.

@saqimtiaz

Yes, three or four times :sweat_smile:

So what is the problem with below example?

<$let
    scope    = "[tag[Filter Operators]]"
    letters  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    cond     = "[subfilter<scope>prefix<currentTiddler>]"
>

<$list filter="[<letters>split[]] :filter<cond>">
<$text text=<<currentTiddler>> /> 
</$list>

</$let>

:filter is a filter run prefix. Filter run prefixes need the filter run to be provided as literal strings, you cannot use variables. If you want to use a variable, then use the filter[] operator.

@Mohammad , I did’t test anything but wouldn’t your “cond” evaluate into:

cond = "[subfilter[tag[Filter Operators]]prefix<currentTiddler>]"

which obviously is foul syntax.

Saq,

So, the below shall give correct answer, but it does not:

\define mac(scope:"[tag[Filter Operators]]")
<$let
    letters  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    cond     = "$scope$ +[prefix<currentTiddler>]"
>

<$list filter="[<letters>split[]filter<cond>]">
<$text text=<<currentTiddler>> /> 
</$list>

</$let>
\end

<<mac>>

@twMat
Actually it will wrap into a macro and one need to be able to pass different scope!
See another example I have given above!

Excuse my stupid question: What can :map be used for?

As they say, Did you “RTFM” :wink:

Two issues that I see:

  1. Are there any filter operators starting with uppercase letters?
  2. You aren’t using a selection constructor inside the :filter run, start it with all[tiddlers] as by default it only gets a single title as input.

Some links to real world examples here on the forum:

1 Like

I tried with <<mac "[tag[Learning]]">> where there are output with uppercase, still no result!

I am not sure if I follow you! do you mean:

cond     = "[all[tiddlers]] +$scope$ +[prefix<currentTiddler>]"

I got the correct result if I go as below

\define mac(scope:"")
<$let
    letters  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		cond     = "[all[tiddlers]] +$scope$ +[prefix<currentTiddler>]"
>

<$list filter="[<letters>split[]filter<cond>]">
<$text text=<<currentTiddler>> /> 
</$list>

</$let>
\end

Note to the cond!

@saqimtiaz , is this the correct solution?

I have concluded this discussion in the original post (first post in this thread )
I appreciate if Saq (@saqimtiaz) kindly read and correct if there is any incorrect conclusion!
Any contribution is welcome! I also kindly ask Brian (@btheado) if kindly have a look and see if these are can be added to tiddlywiki.com documentation!

Looks correct to me.

1 Like

I think the only part that maybe needs to be made more explicit in the docs is that :filter, :map and :reduce only receive a single title as input. So if you want to query all tiddlers, you need to start your filter run with all[tiddlers].

1 Like

I added this to conclusion!

To see if I can contribute helpfully to this discussion, and to further my own understanding, I went back to the documentation, I think it fair to call it “Terse” or “sparing in the use of words”. As I come to understand this better I will need to find my own words to describe them, hopefully I can produce something that will help others. The descriptions reads to me as exactly what someone who already understands it would write, not what something someone who does not understand it needs to read.

Starting with referring to filter filter1 and filter2 would be a good start.

The value of currentTiddler outside the run is available in the variable “…currentTiddler”.

Can anyone show how to use <<..currentTiddler>> "outside the run?

[Edit] Also note https://tiddlywiki.com/#Filter%20Run makes no mention that “Filter Runs can have prefixes” and “Filter Run Prefix” tiddlers also make no mention of ## Filter Expression
which documents other prefixes = + - ~

Example demo

To show the application of this discussion, see the Simple Pagination Two example below.
It accept a filter (with any complexity) and produces a list with a header contains alphabetical index buttons! On click the output will be limited to titles prefixed with that letter.

Code

\define simple-pagination-two(scope:"[all[tiddlers]!is[system]]")
<$let
    letters      = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    cond         = "[all[tiddlers]] +$scope$ +[uppercase[]prefix<currentTiddler>]"
    tempTid      = "$:/temp/pagination"
    titlePrefix  = {{{ [<tempTid>get[text]] }}}
    listfilter   = "[uppercase[]prefix<titlePrefix>]"
    selStyle     = "[<currentTiddler>match<titlePrefix>then[font-weight:bold;color:red;]]"
>

<!-- create header -->
<$list filter="[<letters>split[]filter<cond>]">
<$button style="color:navy;margin:1px;width:2em;height:1.8em;cursor:pointer;">
<span style={{{[subfilter<selStyle>]}}} ><$text text=<<currentTiddler>> /></span>
<$action-setfield $tiddler=<<tempTid>> text=<<currentTiddler>> />
</$button>
</$list>

<!-- generate output -->
<$list 
  filter="[subfilter<__scope__>filter<listfilter>sort[title]]"
  template="$:/core/ui/ListItemTemplate" 
/>
</$let>
\end

To give a try

Remarks

  • Two filter operator is used, cond and listfilter
  • Note to the usecases in
    • filter="[<letters>split[]filter<cond>]"> and
    • filter="[subfilter<__scope__>filter<listfilter>sort[title]]"
  • Some css styles have been used as cosmetic!

Screencast

In the below an example the macro is called with

<<simple-pagination-two "[tag[Filter Operators]] [tag[Filter Run Prefix]]">>

which produces

img_842_msedge

2 Likes