nested macros?

112 views
Skip to first unread message

Abraham Neben

unread,
Jan 6, 2016, 2:31:51 PM1/6/16
to TiddlyWiki
I want to loop over all task types (I have tiddler's called "home", and "work", each tagged as "tasktype"), and for each one, list the names of all tiddlers of that type also tagged as "task". This is instead of simply copying my code as below. How can I do this?

Ugly solution:

!! home
<$list filter="[!has[draft.of]tag[task]!tag[done]tag[home]sort[created]]">

<$checkbox tag="done"> <$link to={{!!title}}><$view field="title"/></$link></$checkbox>

</$list>

!! work
<$list filter="[!has[draft.of]tag[task]!tag[done]tag[work]sort[created]]">

<$checkbox tag="done"> <$link to={{!!title}}><$view field="title"/></$link></$checkbox>

</$list>

Jed Carty

unread,
Jan 6, 2016, 2:43:59 PM1/6/16
to TiddlyWiki
It is much easier if you use a field instead of a tag, like a 'task_type' field set to Home or Work or whatever you want. Then:

<$list filter='[!has[draft.of]tag[task]has[task_type]each[task_type]get[task_type]'>

!!<$view field='task_type'/>

<$list filter='[tag[task]task_type<currentTiddler>]'>


<$checkbox tag="done"> <$link to={{!!title}}><$view field="title"/></$link></$
checkbox>


</$list>
</$list>

So I can show off a bit, if you want something fancier I made a category list plugin I use as a tasklist. There is an example here and the plugin here.

c pa

unread,
Jan 6, 2016, 2:45:27 PM1/6/16
to TiddlyWiki
>> Ugly solution:

Hmmm. That looks like the right solution to me.

To make it better you could wrap it as a macro like this

\define listTaskStatus(taskArea)
<$list filter="[!has[draft.of]tag[task]!tag[done]tag[$taskArea$]sort[created]]">

<$checkbox tag="done"> <$link to={{!!title}}><$view field="title"/></$link></$checkbox>

</$list>
\end

!! home
<<listTaskStatus "home">>

!! work
<<listTaskStatus "work">>

Eric Shulman

unread,
Jan 6, 2016, 4:23:17 PM1/6/16
to TiddlyWiki
On Wednesday, January 6, 2016 at 11:31:51 AM UTC-8, Abraham Neben wrote:
I want to loop over all task types (I have tiddler's called "home", and "work", each tagged as "tasktype"), and for each one, list the names of all tiddlers of that type also tagged as "task". 

You could use nested lists, like this:
<$list filter="[!has[draft.of]tag[tasktype]]" variable="tasktype">
   <$list filter="[!has[draft.of]tag[task]!tag[done]tag
<tasktype>sort[created]]">

      <$checkbox tag="done"> <$link to={{!!title}}><$view field="title"/></$link></$checkbox>
   </$list>
</$list>

* the outer <$list> loops over all tasktypes (i.e., "home", "work" etc.) and sets the variable, "tasktype"
* the inner <$list> loops over all tasks that are not done that are also tagged with the current task tasktype.

Note the angle brackets in the "tag<tasktype>" syntax is what allows you to use a variable value -- rather than the usual literal text -- as the operand of the tag[] filter. Also, using a named variable in the <$list>, instead of the default "currentTiddler", makes the overall meaning of the filter easier to understand.

One more "code style" tip that I sometimes use in my own projects: instead of putting filters and $list contents "inline", it can help to separate the parts into named macros, and then use those macros in the $list widgets.  This approach can make it much easier to understand the code, since it isolates some of the complex syntax and gives them symbolic names that help to emphasize their purpose.  For example, the previous code could be written this way:

\define types() [!has[draft.of]tag[tasktype]]
\define tasks() [!has[draft.of]tag[task]!tag[done]tag<tasktype>sort[created]]
\define link()  <$link to={{!!title}}><$view field="title"/></$link>
\define check() <$checkbox tag="done"> <<link>></$checkbox>

<$list filter=<<types>> variable="tasktype">
   
<$list filter=<<tasks>>>
     
<<check>>
   
</$list>
</
$list>

While this coding style is not as compact, it is much more readable, as well as making it easier to do things like change the filter definitions or the output format. For example, you could add a "priority" field to your task tiddlers, and then then simply change this one line:
\define tasks() [!has[draft.of]tag[task]!tag[done]tag<tasktype>sort[priority]]
without having to find the right place buried "inline" in the nested $list syntax.

enjoy,
-e

Tobias Beer

unread,
Jan 6, 2016, 5:08:17 PM1/6/16
to tiddl...@googlegroups.com
Hi Eric,
 
One more "code style" tip that I sometimes use in my own projects: instead of putting filters and $list contents "inline", it can help to separate the parts into named macros, and then use those macros in the $list widgets.

Thanks for the useful tip.

Another way to do this for a more narrowly defined scope would be to use the vars widget, e.g:

<$vars
types = "[!has[draft.of]tag[tasktype]]"
tasks = "[!has[draft.of]tag[task]!tag[done]tag
<currentTiddler>sort[created]]"
link = """<$link to={{!!title}}><$view field="title"/></$link>"""
check = """<$checkbox tag="done"> <
<link>></$checkbox><br>""">
<dl>
<$list filter=<
<types>>>
<dt><<link>></dt>
<$list filter=<
<tasks>>>
<dd><<check>></dd>
</$list>
</$list>
</dl>
</$vars>

Or using headings instead of a definition list:

<$vars
types = "[!has[draft.of]tag[tasktype]]"
tasks = "[!has[draft.of]tag[task]!tag[done]tag
<currentTiddler>sort[created]]"
link = """<$link to={{!!title}}><$view field="title"/></$link>"""
check = """<$checkbox tag="done"> <
<link>></$checkbox><br>""">
<$list filter=<
<types>>>
<h2><<link>></h2>
<$list filter=<
<tasks>>>
<
<check>>
</$list>
</$list>
</$vars>

Best wishes,

Tobias. 

Tobias Beer

unread,
Jan 6, 2016, 5:14:47 PM1/6/16
to tiddl...@googlegroups.com
Hi Abraham,

Arguably the easiest way is to use tobibeer/xlist:

<<xlist
groups:"[tag[tasktype]sort[title]]"
filter:"[!has[draft.of]tag[task]!tag[done]sort[created]]"
>>

Best wishes,

Tobias. 
Reply all
Reply to author
Forward
0 new messages