Interesting Code Patterns? Handling the emptyMessage condition in the ListWidget Body, a CASE structure, complex formulas

271 views
Skip to first unread message

TonyM

unread,
Jul 26, 2019, 12:20:31 AM7/26/19
to TiddlyWiki
I just wanted to share this code pattern I just discovered for Handling the emptyMessage condition in the ListWidget Body.

Sometimes the way we write Filters the only way to proceed is to use the emptyMessage to deal with the null case.

If the Null case response requires multiple lines of wiki text it gets a little messy

\define macrodef()
If condition not met
\end


<$list filter="condition" emptyMessage=<<macrodef>> >
If Condition met
</$list>
The macro def must be at the top and it is removed from the list widget


OR
<$list filter="condition" emptyMessage="""

If condition not met
""">
If Condition met
</$list>
This makes me nervous :)

So I developed this method/pattern
<$list filter="[is[current]tagging[]] ~[[::false]]" variable=result>
   <$list filter="[
<result>prefix[::]]" variable=case>
        Do this if <
<case>>
   </$list>
   <$list filter="[
<result>!prefix[::]]" variable=case>
        Process tiddler "<
<case>>"<br>
   </$list>
</$list>
Using the unlikely tiddler title "::false" to flag the empty set condition.
In this case the null case is executed once and the "no null case" as many times as needed.

And did I mention "case"?

This structure also allows us to build a CASE structure with a default behaviour.

That is if a variable or field contains one of a number different values, and you wish to respond differently for each

<$list filter="[<casevariable>] ~[[::false]]" variable=case>
   <$list filter="[
<case>prefix[::false]]" variable=case>
        Do this if no case value
   </$list>
   <$list filter="[
<case>prefix[caseone]]" variable=case>
        Process "caseone"
<br>
   </$list>
   <$list filter="[
<case>prefix[casetwo]]" variable=case>
        Process "casetwo"
<br>
   </$list>
   <$list filter="[
<case>prefix[casethree]]" variable=case>
        Process "casethree"
<br>
   </$list>
<!-- Even this -->
   <$list filter="
[<case>prefix[casetwo]] [<case>prefix[casethree]]" variable=case>
        Process "casetwo" and "casethree"<br>
   </$list>
</$list>

With the mathematics operators 

More will be possible?

Regards
Tony




TonyM

unread,
Jul 26, 2019, 12:59:13 AM7/26/19
to TiddlyWiki
Post Script the above is not tested.

Mohammad

unread,
Jul 26, 2019, 2:18:39 AM7/26/19
to TiddlyWiki
Hi Tony
This is interesting!

Could you give some simple examples?

We need to wrap inside a macro to present a construct like

<<select-case  condition array-of-cases>>


What do you think?


I use a lot $list as 

if filter-not-empty do-this else do-that

  • filter is not empty do what is given inside $list widget
  • filter is empty go for emptyMessage



--Mohammad

TonyM

unread,
Jul 26, 2019, 7:36:44 PM7/26/19
to TiddlyWiki
Mohamad,

I have rewritten the code pattern to suit your "else" use case

 
I use a lot $list as 

if filter-not-empty do-this else do-that

  • filter is not empty do what is given inside $list widget
  • filter is empty go for emptyMessage
 
<$list filter="[<casevariable>] ~[[::else]]" variable=case>
 
   <$list filter="[<case>!prefix[::else]]" variable=case>
        filter-not-empty do-this
    </$list>
  <$list filter="[
<case>prefix[::else]]" variable=case>
        else do-that
   </$list>
</$list>
Note: untested

Regards
Tony

TonyM

unread,
Jul 26, 2019, 7:48:31 PM7/26/19
to tiddl...@googlegroups.com
Mohammad,
 
We need to wrap inside a macro to present a construct like

<<select-case  condition array-of-cases>>
 

In someways I am suggesting you do not need to make a "select-case macro " because the whole case structure including the empty case can be written inside the one outer list object. Thus it may be included something like this
{{invoice-total}}
where the case test various conditions and generates a result eg if tax applies etc...

However if you do want to make a macro as in your example the case structure will still need to know how to handle your array-of-cases

I would think its more like this;
\define if-else-test(filter)
<$list filter="[[$filter$]] ~[[::else]]" variable=case>

   
<$list filter="[<case>!prefix[::else]]" variable=case>
       
       filter
-not-empty do-this for each result
   
</$list>

  <$list filter="[<case>prefix[::else]]" variable=case>
        else do-that
   </
$list>
   
<!-- other cases if desired -->
</$list>
\end
<<if-else-test "filter">>
note: untested

Regards
Tony

A Gloom

unread,
Jul 26, 2019, 10:17:46 PM7/26/19
to TiddlyWiki
yes!!  more!!  I'll be srudying this...

Mohammad

unread,
Jul 27, 2019, 12:39:30 AM7/27/19
to TiddlyWiki
Hi Tony!
 This is great and needs some examples to explore the pros and cons!
By the way as you said the application may vary case by case and a macro may not be a good option.

--Mohammad

TonyM

unread,
Jul 27, 2019, 2:42:56 AM7/27/19
to TiddlyWiki
Mohammad,

I some ways I built this so the empty message did not require a macro, to keep all the logic in the one block.

I would imaging people would copy such a block as follows
<$list filter="[<casevariable>] ~[[::false]]" variable=case>
   <$list filter="[
<case>
prefix[::false]]" variable=case>

        Do this if no case value
   </$list>
   <$list filter="[<case>!prefix[::false]]" variable=case>
        Do this for every case except empty/false
   </$list>
   <$list filter="[
<case>prefix[caseone]]" variable=case>
        Process "caseone"
<br>
   </$list>
   <$list filter="[
<case>prefix[casetwo]]" variable=case>
        Process "casetwo"
<br>
   </$list>
   <$list filter="[
<case>prefix[casethree]]" variable=case>
        Process "casethree"
<br>

   </$list>
<!-- Even this -->
   <$list filter="[
<case>prefix[casetwo]] [<case>prefix[casethree]]" variable=case>
        Process "casetwo" and "casethree"
<br>
   </$list>
</$list>
Then change add remove as needed for their application

However in the unlikely case people need to use "nested case statements or reuse them, here is a Quick macro version
\define in-cases-of(case-filter)
<$list filter="$case-filter$ ~[[::false]]" variable=case>

   
<$list filter="[<case>prefix[::false]]" variable=case>
       
Do this if no case value
   
<
/$list>
   <$list filter="[<case>!prefix[::false]]" variable=case>
        Do this for every case except empty/
false
   
</$list>

   <$list filter="[<case>prefix[caseone]]" variable=case>
        Process "caseone"<br>
   </$list>

   
<$list filter="[<case>prefix[casetwo]]" variable=case>
       
Process "casetwo"<br>

   
</$list>

   <$list filter="[<case>prefix[casethree]]" variable=case>
        Process "casethree"<br>
   </
$list>

<!-- Even this -->
   
<$list filter="[<case>prefix[casetwo]] [<case>prefix[casethree]]" variable=case>
       
Process "casetwo" and "casethree"<br>
   
</$list>
</
$list>
\end

<<in-cases-of "[{!!tiddler-mode}]">>
Which still needs editing for the specific situation

CHanges most likely would be only
  • Change the values for caseone casetwo and casethree to those you want to use
  • Add remove other responses to different case values or combinations thereof.
Additional interesting patterns here
  • The above method of passing filters to a macro as a parameter, allows you to pass tiddler content, field content, literal values, variable values, macronames etc.. which sometimes suddenly results in a macro for one purpose suddenly be capable of another purpose.
In a similar way we can pass a filter to a macro as follows

\define my-macro(filter)
{{{ $filter$ }}}
{{{ $filter$ ||templatename}}}
\end
or
\define my-macro(filter template)
{{{ $filter$ }}}
{{{ $filter$ ||$templatename$}}}
\end

Once again all this is untested but based on experience.

Regards
Tony

Mohammad

unread,
Jul 27, 2019, 5:30:23 AM7/27/19
to TiddlyWiki
Thanks Tony!
It works great! I also used a simple version as this


\define case(x)
<$list filter="[<__x__>prefix[one]]">
This is case one.
</$list>
<$list filter="[<__x__>prefix[two]]">
This is case two
</$list>
<$list filter="[<__x__>prefix[three]] [<__x__>prefix[four]]">
This is case three and four
</$list>
\end

<<case "one">>
<<case two>>
<<case "three tag">>
<<case "four dogs come">>

The prefix is case sensitive and it is good
but it also handle cases like oneWord where one is part of another word!

--Mohammad

TonyM

unread,
Jul 27, 2019, 5:50:34 AM7/27/19
to TiddlyWiki
Mohammad,

Yes the single prefix statement allows oneWord where "one" is the prefix of another "word"!

And to do what you say more literally you could use "contains[one]"

This of course can be stopped if required with

filter="[<__x__>prefix[one]suffix[one]]"


If we ever get an equals[] operator this would become
[<__x__>equals[one]]
Not real yet :)

Regards
Tony

Mohammad

unread,
Jul 27, 2019, 6:08:35 AM7/27/19
to tiddl...@googlegroups.com


On Saturday, July 27, 2019 at 2:20:34 PM UTC+4:30, TonyM wrote:
Mohammad,

Yes the single prefix statement allows oneWord where "one" is the prefix of another "word"!

And to do what you say more literally you could use "contains[one]"

This of course can be stopped if required with

filter="[<__x__>prefix[one]suffix[one]]"


This does the job!

Mat

unread,
Jul 27, 2019, 8:05:33 PM7/27/19
to TiddlyWiki
Interesting pattern. should be useful.

If we ever get an equals[] operator this would become
[<__x__>equals[one]]
Not real yet :)

Would regexp[^one$] suffice? 

<:-)

TonyM

unread,
Jul 27, 2019, 8:11:39 PM7/27/19
to TiddlyWiki
Mat,

I expect it would suffice. I assume that is an equivalent for equal or prefix[one]suffixe[one]]?

There is a bit of a barrier to all users using regexp. What would be nice is if some of the common ones like you demonstrated were documented for general users to use. Especially for the cases where it helps address a shortcoming.

If you know regex well I could generate a list of desirable tests for you to match?

Regards
Tony

Mat

unread,
Jul 27, 2019, 8:44:48 PM7/27/19
to TiddlyWiki
On Sunday, July 28, 2019 at 2:11:39 AM UTC+2, TonyM wrote:
Mat,

I expect it would suffice. I assume that is an equivalent for equal or prefix[one]suffixe[one]]?

AFAIK it is used for exact match so it is not equivalent to prefix-suffix.
 
If you know regex well I could generate a list of desirable tests for you to match?

I barely even know regexp badly.  That is basically the only one I know for exctly the reason of being able to make an exact comparison. BUT don't take my word for it, I just found it on the web...

<:-)

TonyM

unread,
Jul 27, 2019, 9:19:18 PM7/27/19
to TiddlyWiki
Mat - thanks for your Idea never the less

By the way prefix[one]suffix[one]] 

Is the closes to exact match we have. I expect onesomethingone will bypass this.

regexp[^one$]

is thus very helpful

So the case can MAY now look like this but I expect the :: needs to be removed and "false" not a possible value because ":" is possibly a regex value.


<$list filter="[<casevariable>] ~[[false]]" variable=case>
   <$list filter="[
<casevariable>regexp[^false$]]" variable=case>

        Do this if no case value
   </$list>
   <$list filter="[<case>regexp[^caseone$]]" variable=case>
        Process "caseone"
<br>
   </$list>
   <$list filter="[
<case>regexp[^casetwo$]]" variable=case>
        Process "casetwo"
<br>
   </$list>
   <$list filter="[
<case>regexp[^casethree$]]" variable=case>
        Process "casethree"
<br>

   </$list>
<!-- Even this -->

   <$list filter="[
<case>regexp[^casetwo$]] [<case>regexp[^casethree$]]" variable=case>
        Process "casetwo" and "casethree"
<br>
   </$list>
</$list>


Regards
Tony

TonyM

unread,
Jul 31, 2019, 9:16:25 AM7/31/19
to TiddlyWiki
Folks,

Ad a result of Jeremy adding a new match operator to 5.1.20 the case statements in this code pattern will be even more user friendly.

First we would say

[<case>prefix[caseone]suffix[caseone]]

Now we would say
[<case>regexp[^caseone$]]

But this Will become which is easier to remember
[<case>match[caseone]]

The regex example still points us to the best approach for more complex tests but match will work for many common cases.

I will now abandon only testing the negative in binary comparisons such as
[<var>] -[[false]]

becomes
[<var>match[true]]

the case insensitive option may also help when var or [{$:/temp/tiddler}] was provided by the user in case they entered tRue and other combinations by mistake.

Thanks Jeremy
Tony

Mohammad

unread,
Jul 31, 2019, 1:34:59 PM7/31/19
to TiddlyWiki
Thanks Tony!
 This is great for code readability!

Cheers
Mohammad

TonyM

unread,
Jul 31, 2019, 7:16:23 PM7/31/19
to tiddl...@googlegroups.com
Your welcome

So on 5.1.20 
<$list filter="[<casevariable>] ~[[false]]" variable=case>
   <$list filter="
[<case>match[false]]" variable=case>

        Do this if no case value
   </$list>
   <$list filter="[<case>match[caseone]]" variable=case>
        Process "caseone"
<br>
   </$list>
   <$list filter="[
<case>match[casetwo]]" variable=case>
        Process "casetwo"
<br>
   </$list>
   <$list filter="
[<case>match[casethree]]" variable=case>
        Process "casethree"<br>

   </$list>
<!-- Even this -->

   <$list filter="
[<case>match[casetwo]] [<case>match[casethree]]" variable=case>
        Process "casetwo" and "casethree"
<br>
   </$list>
</$list>

Regards
Tony

@TiddlyTweeter

unread,
Aug 1, 2019, 6:11:35 AM8/1/19
to tiddl...@googlegroups.com
An aside in this thread.., but not irrelevant.

Mat: I barely even know regexp badly.  That is basically the only one I know for exctly the reason of being able to make an exact comparison. BUT don't take my word for it, I just found it on the web..

Regex is one of few areas of computing I'm any good at.

I'd like to comment that in one way TW can be seen is as a Regex Machine + a very good AST.

Regular expressions are frustrating at first in their scope if you never used them before. Especially when more complex, they absolutely need testing against data because they do not work using procedural logic. 

But they are the single most powerful tool for text matching and manipulation we have.

I do think that slightly better understanding of regular expressions amongst TW users would leverage it better. 

When you understand them they are very economical.

Dimmi (tell me) what would be useful for you to better understand Reggie? I'm willing to lay it out.

TT





@TiddlyTweeter

unread,
Aug 1, 2019, 9:00:38 AM8/1/19
to TiddlyWiki
Now we would say
[<case>regexp[^caseone$]]


The difference here is that  is the marker for "start of string" and  "end of string", regex meta characters.


But there would be no difference between  [<case>regexp[caseone]]  and  [<case>match[caseone]] 


So you are not really comparing equal cases. It seems a bit odd to advance "match" when its simply a sub-set in this case.

I'm sure there are useful cases, but that is not one of them.

Josiah

TonyM

unread,
Aug 1, 2019, 10:44:28 AM8/1/19
to TiddlyWiki
Josiah

I would not underestimate the value of a plain English operator like match for easy to read tests especially when they control visibility and structure in code.

On regex you could give the community A great resource if you provide 10 to 20 top regex tests we may want to use. I could brainstorm some desirable ones.

Regards
Tony

@TiddlyTweeter

unread,
Aug 1, 2019, 11:11:53 AM8/1/19
to TiddlyWiki
TonyM wrote:

I would not underestimate the value of a plain English operator like match for easy to read tests especially when they control visibility and structure in code.


Don't disagree. But its not a straw man.  Its the intelligent man--when you need her. Your example triumphed plain English ignoring regex does plain already.
 

On regex you could give the community A great resource if you provide 10 to 20 top regex tests we may want to use. I could brainstorm some desirable ones.


I'd happily do it. But I need to know what is needed. What is relevant?

TT

Mohammad

unread,
Aug 1, 2019, 12:01:49 PM8/1/19
to tiddl...@googlegroups.com
Josiah,
I would also appreciate if you could provide examples of common and useful pattern of regexp in TW!
You favored me and provided a help page for SnR in Tiddler Commander!

I know regexp is very powerful but in tiddlywiki.com there is little documentation on that!

You can have a daily post like An Example a Day Using regexp with Tiddlywiki  :-)

Cheers
Mohammad 

@TiddlyTweeter

unread,
Aug 1, 2019, 12:12:59 PM8/1/19
to tiddl...@googlegroups.com
I like regular expressions a lot.

I'm not clear what people need though.

The kind of thing I do with them I doubt most people would be interested in.

I'll think about it. 

Maybe what is needed is an overview of the use of regex in TW (which is much wider actually than operators)? I think its the lack of a broad understanding of their ubuiquity that is in the way.

Josiah

@TiddlyTweeter

unread,
Aug 1, 2019, 12:27:35 PM8/1/19
to TiddlyWiki
An issue in TW in filters with regex is that "[" "]" are needed too in regex for "character classes" (e.g. [a-f, A-G]) to get them to work requires a bit more than normal regex since you can't use square brackets directly in TW regex filters, otherwise its works as expected.

A few things like that I can explain how to deal with.

I'm now thinking about it as there seems to be interest.

J.

Mohammad

unread,
Aug 1, 2019, 12:44:30 PM8/1/19
to TiddlyWiki
Yes that is true!
Using SnR when I want to rename tiddlers like tid01/example01 to tid01\example01 or change a filter [tag[mytag]] to [tag<mytag>]
I encounter problem.

By the way, finding a string ended by say myword or contains a special format like date or number are among cases we cannot use the search or prefix or other filter operator.

--Mohammad

TonyM

unread,
Aug 1, 2019, 6:04:18 PM8/1/19
to TiddlyWiki
Josiah,

I am busy at the moment but I am sure I can brainstorm some cases for regex. 

Does defining a macro containing the regex then using regexp<macro> resolve the use of "[ ]"?

Off the top of my head
  • The equal test (already)
  • The Not equal test if there is one
  • Searching for common tiddlywiki patterns `{{ }} {{!! << [[ ||` and when they have matching braces extract what is between them
    • Imagine if we could search for the use of templates `{{something||template}}`
  • Given a keyword find "keyword:" "[[keyword]]" etc...
  • Find keyword pairs eg keyword="value" keyword:"value" keyword:value need to account for ' "" """
    • Search values and get values (less the keyword)
  • Find the delimiters in use eg [[]] "," "/"
  • Count the number of delimiters eg how many "/" in a title
Any thing which results in a numeric output will have more value than ever with the introduction of maths operators.

Regards
Tony

TonyM

unread,
Aug 1, 2019, 6:12:12 PM8/1/19
to TiddlyWiki
And

With  2019-08-01 give  20190801 (remove delimiters
or return 
2019
08
01

Do the reverse? add "-" tt position 4 6 8

Regards
Tony

@TiddlyTweeter

unread,
Aug 3, 2019, 5:34:09 AM8/3/19
to tiddl...@googlegroups.com
Ciao TonyM

I sat a bit with this and your last post that lists useful requests I've noted.

I think the issue, at root, is "regex" is a powerful pattern matching "language" built into JavaScript that TW has access to.

And its worth noting that a lot of TiddlyWiki, behind the scenes, uses it extensively---most "pragma" for instance use regexes within an "AST" (a framework that controls them) in applying WikiText.

Regex as a [filter] is interesting and useful, but I'm not sure it can be leveraged without slightly better understanding what regex can and can't do.

Important to note is regex has NO understanding of maths at all. YET you can use it, for instance, to support a system that needs proper accurate dates, including leap years and month days from 1000 to 9999 in both the Gregorian and Julian calanders. But it does NOT do it though calculation. It does it through pattern matching only.

Its this apparent weirdness in regex I think that is very confusing if you looking for a logical operator that can say "yes" or "the total is". That is not its strength and it will confound you thinking it might be (because it sort of looks "intelligent"--its actually more like using crossword-puzzles).

So maybe what is perhaps needed most are some basic examples of what regex patterns are and how they match example data?

BTW, the examples you ask about, when they involve matching strings in TW (not evaluation or math), are all easily doable via regex.

Thoughts
Josiah

Mohammad

unread,
Aug 3, 2019, 6:49:01 AM8/3/19
to TiddlyWiki
Added to TW-Scripts!

Mohammad

unread,
Aug 3, 2019, 6:52:03 AM8/3/19
to TiddlyWiki
Tony,
 One question, how do you propose to implement the below construct using $list widget

if a>b then
 
do this part one
else if a<b
 
do this part two
end




or only 

if a< b then
 
do this true part
end



Now using match we can implement if a=b.

--Mohammad

TonyM

unread,
Aug 3, 2019, 7:30:07 AM8/3/19
to TiddlyWiki
Mohammad,

Your first resort would be to the reveal widget since it already permits such comparisons. I had raised the development of less than and greater than operators but there is a real issues these raise because such tests need to take account of the complexity inherent in numbers. I am sure JavaScript can help.

Never the less I will give your questions some thought and see if I can craft a method with existing features. Then if we can't get something that resembles plain English or is not too complex we can ask the developers.

One method may be using one of the sort operators then testing the first in the list. One trick could be to test if the original list ie two items is in the same order after sorting or not. If such tests can be written in a subfilter they could be easy to read
Eg [<var1>] [<var2>] +[subfilter[firstgreater]]
Is true or not.

Thanks for the challenge, I hope others take it on as well.

Though do remember the rereleased version of Evans formulas plugin can do all of this.

Regards
Tonu

Mohammad

unread,
Aug 3, 2019, 9:05:46 AM8/3/19
to TiddlyWiki
Yes, the reveal widget is one solution!
It is important to have a readable and maintainable code!

--Mohammad

Mohammad

unread,
Aug 3, 2019, 9:55:48 AM8/3/19
to TiddlyWiki
Tony
Have a look here, then else operator

Mohammad

unread,
Aug 3, 2019, 10:15:09 AM8/3/19
to TiddlyWiki

TonyM

unread,
Aug 3, 2019, 8:00:11 PM8/3/19
to TiddlyWiki
Great stuff

Message has been deleted

TonyM

unread,
Aug 4, 2019, 2:11:03 AM8/4/19
to TiddlyWiki
Mohammad,

Comparing two values for which is the greater - 5.1.20 ONLY because it uses match and min operators

<$set name=input1 value=3>
<$set name=input2 value=5>


<$list filter="=[
<input1>!match<input2>]" emptyMessage="equals">
   <$list filter="=[
<input1>min<input2>match<input1>]">
      Input 1 = Minimum
   </$list>
   <$list filter="=[
<input1>max<input2>match<input1>]">
     Input 1 = Maximum
   </$list>
</$list>

</$set></$set>


Tony

Mohammad

unread,
Aug 4, 2019, 3:02:54 AM8/4/19
to TiddlyWiki
Really smart solution!

:-)

I am working to see how we can do branching using only $list widget and it seems
It can be used in many cases!

The $list widget seems NOT a simple iterator and almost do many things just its name is misleading for many users

--Mohammad

Mohammad

unread,
Aug 4, 2019, 3:04:49 AM8/4/19
to TiddlyWiki
Added to TW-Scripts

Mohammad

unread,
Aug 4, 2019, 3:11:08 AM8/4/19
to TiddlyWiki
There is a small caveat.
One should take care of Empty value! The empty value is interpreted as 0!


Reply all
Reply to author
Forward
0 new messages