Possible error in action-listops widget documentation

The documentation for the <$action-listops> widget states:

Both of the following yield the same result:

<$action-listops $subfilter="-[[List Item]]"/>
<$action-listops $subfilter="+[remove[List Item]]"/>

However, these behave differently:

  • The :except filter run prefix removes its output titles from the list of input titles; here there is no split[ ] so the single item “List Item” will be removed.
  • The remove operator treats its parameter as an array and thus will remove two items, “List” and “Item”, from the list.

Thus, if the original list was [[List Item]] List [[List My Item]] Item, then:

  • By using -[[List Item]] we would end up with List [[List My Item]] Item
  • By using +[remove[List Item]] we would end up with [[List Item]] [[List My Item]]

Am I right that the documentation is incorrect here, or have I overlooked something?

(Of course, if there were no space in the example, such as if it were “ListItem” or “List-Item”, then the two versions would have the same effect.)

Edit:

To be clear, this post is about the quoted part of the documentation for the <$action-listops> widget being incorrect, and not about whether the remove filter operator (or :except filter run prefix) function correctly. (As far as I can tell, they function correctly.)

Additional discussion and testing of the remove operator (see especially @TW_Tones’s post below) seems to show that the remove operator treats its parameter as a title list, which we assume to be how it is intended. However, the documentation for the remove operator doesn’t say it’s parameter is a “title list” but only that it is an “array”, which unclear (and even the examples don’t make it clear that it’s a title list as opposed to, say, an array of space-separated values). Thus, in addition to the correction needed to the <$action-listops> widget documentation as pointed out in the original post, I think the remove filter operator documentation could use an update to specifically say the parameter is specifically a title list.

  • We have not decided what to write in place of the incorrect portion of the <$action-listops> widget documentation. The purpose of that part of the documentation was to give examples of ways to use the widget to remove values from a list field, so my take would be that it can say that you can use -[[List Item]] or +[remove[Item]] to remove items from the list, but also say that if the item you want to remove has spaces, you have to either use -[[List Item]] or use remove with a soft parameter (such as +[remove{tid!!list}]), whereas +[remove[Item1 Item2]] works great to remove multiple items as long as none of the items has a space (and the same is achievable as -Item1 -Item2).

You’re absolutely correct. I’m guessing that a pull request for the documentation would be well received.

You are right. Here’s some code to test it. There should be tests in the GH repo. But it seems we have missed that one.

test-action-listops.json (727 Bytes)

If you look closely at the remove[] operator, its parameter is described as;

array =an array of items to remove

So as I read it;

  • you need to delimit the beginning and end of titles in the parameter
  • You can’t do this as a simple parameter because you can’t use [[]] in a parameter value.
  • What does it mean my items?, it is not saying titles

I have being making further tests, but the above code does not help using the different forms. I will post my examples and learnings in this tiddler soon.

Result

It is possible to use remove to achieve the OT, you can do it for a single title, rather than removing strings/words by defining the parameter as follows;

\procedure setContent() <$action-setfield $field=test $value="List [[List my item]] [[List Item]] Item"/>
\define list-item() [[List Item]]

<$button actions=<<setContent>>>
Set Content
</$button>
<hr>


<$button>
<$action-listops $field=test $subfilter="+[remove<list-item>]"/>
<$text text="+[remove<list-item>]"/>
</$button>

test output = '<$text text={{!!test}}/> ''expect" `List [[List my item]] Item`
Here is my full test suit
\procedure setContent() <$action-setfield $field=test $value="List [[List my item]] [[List Item]] Item"/>

\define list-item() [[List Item]]
\function list.item() [[List Item]]
\function list.item2() "List Item"

<$button actions=<<setContent>>>
Set Content
</$button>
<hr>

# <$button >
<$action-listops $field=test $subfilter="-[[List Item]]"/>
<$text text="-[[List Item]]"/>
</$button>
# <$button>
<$action-listops $field=test $subfilter="+[remove<list-item>]"/>
<$text text="+[remove<list-item>]"/>
</$button>
# <$button >
<$action-listops $field=test $subfilter="+[remove[List Item]]"/>
<$text text="+[remove[List Item]]"/>
</$button>
# <$button>
<$action-listops $field=test $subfilter="+[remove<list.item>]"/>
<$text text="+[remove<list.item>]"/>
</$button>
# <$button>
<$action-listops $field=test $subfilter="+[remove<list.item2>]"/>
<$text text="+[remove<list.item2>]"/>
</$button>

test output = '<$text text={{!!test}}/>' ''expect"'' `List [[List my item]] Item`

Conclusion

I am not sure remove[] is so much as broken as not sufficiently documented, to “fix it” could cause existing code to fail.

  • As it stands, I think we can use remove[] to remove one or more tokens or words from a string, as titles, not in titles (needs further testing and anaysis).

It would be worth reviewing other operators that accept an array or list as the parameter.

How the remove[] operator currently works.

The parameter needs to contain appropriately delimited titles to work. Use a macro definition containing the title list without any TiddlyWiki Script, to include items containing spaces.

[Post Script]
As the full test suit demonstrates functions do not work to set the appropriate title.

  • I could see the introduction of an alternative delimiter that is valid in the remove operator parameter for titles eg;
remove[`List Item`] OR remove[`List Item` `other title`]
  • Treat backtick as [[/]]
    Being helpful, to bridge the gap. Perhaps in other operators with list/array parameters.

I thought, mistakenly, from the examples in the documentation, that the remove operator essentially used a space( )-separated array… it didn’t even occur to me that it actually a title list.

The following test code confirms that the “remove” operator treats its parameter as a title list:

<$let list1="one 2 [[two 2]] two three 4" list2="[[two 2]] 2">
<$list filter="[enlist<list1>remove<list2>]" join="<br>" />
</$let>

In my opinion, the remove operator documentation should also be updated to specify that its parameter is a title list of titles to be removed. While a title list is a kind of array, using the term “title list” would be more specific and clear than the term “array”. It would also allow linking to the title list documentation page for readers who may be unsure of what precisely “title list” means.

(If I get time over the weekend, perhaps I will figure out exactly how to correctly create a PR and follow all the standards so that I can correct small things like this myself.)

1 Like

We were working on this at the same time, see my last post updated.

If you have a github login, and “registered as a contributor” you can;

Edit a documentation tiddler on tiddlywiki.com and you will start the PR process otherwise look at other approaches here and in the Documentation Topic.

So, assuming that the parameter for the remove filter operator is a title list (and that this is the intended design), we have identified in this topic two parts of the documentation that could use a change:

  1. The remove documentation should be specific about its parameter being a title list (could also link to the “title list” page)
  2. The <$action-listops> widget incorrectly states that [remove[List Item]] and -[[List Item]] will do the same thing (in the $subfilter attribute). This is what the original post was about.

For the action-listops documentation, what should we change that part of the documentation to say?

My thought is, since the purpose of that part of the documentation was to give examples of how to remove items from a list field using the <$action-listops> widget, it should still give both of those examples (except filter run prefix and remove operator), but it should note the difference rather than say they yield the same result. For example, instead of this:

Similarly, if an element is to always be removed when it is present, the - / :except filter run prefix can be used. Both of the following yield the same result:

<$action-listops $subfilter="-[[List Item]]"/>
<$action-listops $subfilter="+[remove[List Item]]"/>

It can say something like this:

Similarly, if an element is to always be removed when it is present, the - / :except filter run prefix can be used:

<$action-listops $subfilter="-[[List Item]]"/>

Additionally, the remove operator can be used:

<$action-listops $subfilter="+[remove[Item]]"/>

Note that the remove operator treats its parameter as a title list; therefore, remove[List Item] doesn’t remove “List Item” like one might expect, but instead removes tiddlers in the title list “List Item”, that is, “List” and “Item”. Both of the following yield the same result:

<$action-listops $subfilter="-Item1 -Item2"/>
<$action-listops $subfilter="+[remove[Item1 Item2]]"/>

To remove a list item that contains a space, use the - / :except filter run prefix instead.

But maybe this is too lengthy?

One thing to note is there are two ways already documented for using the listops one uses the subfilter, and more suited to -[[remove me]] and the other is the filter perhaps more suited to the list..remove[remove me]] or the list -[[remove me]].

  • Often the remove title would use a variable like currentTiddler remove<currentTiddler>]

Any documentation updates need to take account of this.

Looks like the proposal that came up long before I got here is relevant again. Quotes as filter parameter delimiters? - #17 by TW_Tones (I personally like the parentheses idea, except for the fact that it seems common enough to use parentheses in tiddler titles, plus they could be often used in regular expressions just like [].)

As for figuring out the fix for the documentation… priorities… maybe one of these weekends…

I have created a pull request with a documentation update here:

Feel free to comment there if you would like to see further improvements.

That looks reasonable.

Here are some notes to consider.

Listops $subfilter parameter.

Using the $subfilter parameter for a field is a “filter run” that is appended to the original list, equivalent to the $filter form, with the initial list given, where;

  • $field=listfield $subfilter="+[remove[list]" is equivalent to
  • $field=listfield $filter="[subfilter{!!listfield}] +[remove[list]"

Thus the $subfilter is what follows the original list, and thus needs only list the changes, where the $filter needs you iterate the list then the changes.

  • This is why we need to use a filter run prefix, if we wish to alter an existing value in the list.
  • If all that you provide is a few titles they become part of the new list.
    • `$field=listfield $subfilter="[[new title]] another-title"

remove operator itself

Perhaps we should add something in the remove operator, as far as I can see it is the only filter operator called an “array”, I would be tempted to say;

  • To remove one or more titles delimited by [[tiddler title]] use a variable containing the list, of titles +[remove<list-variable>]
    or field reference +[remove{!!listfield}]
    • These are “filter runs” so as to apply the “remove” to all titles in the existing list.

I think “title list” is more precise than “array” and should be the preferred terminology. I did however stumble upon the use of “array” on this page that about listops filters more broadly, which suggests that it’s basically just a synonym; perhaps the “title list” page could simply have a note in it saying 'also called “array” ’ or similar, and then other places that use the term “array” can link to the “title list” page to make it clear what is meant by “array”.

Thanks for taking this on. Sorry I haven’t gotten around to the prerequisites (for PRs) yet. (One of these days!) The changes to the wording in response to my feedback look good to me.