From 0c24e2f5f1c0566074bf514de454e135bd92a9ad Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Wed, 19 Mar 2025 16:14:54 +0000 Subject: [PATCH] Introduce round brackets for multi-valued filter operands Allowing us to drop the varlist operator --- core/modules/filters.js | 26 +++++++++++++++++- core/modules/filters/title.js | 6 ++++- core/modules/filters/varlist.js | 27 ------------------- .../tiddlers/system/DefaultTiddlers.tid | 3 +-- .../data/let-filter-prefix/ResultList.tid | 2 +- .../ResultListUnnamedVariable.tid | 2 +- .../MissingVariable.tid | 4 +-- .../MultiValuedFunction.tid | 2 +- .../MultiValuedOperands.tid | 18 +++++++++++++ .../data/multi-valued-variables/Simple.tid | 2 +- .../filters/syntax/Let Filter Run Prefix.tid | 2 +- .../tiddlers/filters/varlist Operator.tid | 14 ---------- .../tiddlers/system/DefaultTiddlers.tid | 3 +-- .../variables/Multi-Valued Variables.tid | 8 +++--- .../tw5.com/tiddlers/variables/Variables.tid | 2 +- .../tw5.com/tiddlers/widgets/LetWidget.tid | 8 +++--- 16 files changed, 66 insertions(+), 63 deletions(-) delete mode 100644 core/modules/filters/varlist.js create mode 100644 editions/test/tiddlers/tests/data/multi-valued-variables/MultiValuedOperands.tid delete mode 100644 editions/tw5.com/tiddlers/filters/varlist Operator.tid diff --git a/core/modules/filters.js b/core/modules/filters.js index 62f6e7213..7fb2f4834 100644 --- a/core/modules/filters.js +++ b/core/modules/filters.js @@ -38,7 +38,7 @@ function parseFilterOperation(operators,filterString,p) { operator.prefix = filterString.charAt(p++); } // Get the operator name - nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/); + nextBracketPos = filterString.substring(p).search(/[\[\{<\/\(]/); if(nextBracketPos === -1) { throw "Missing [ in filter expression"; } @@ -82,6 +82,10 @@ function parseFilterOperation(operators,filterString,p) { operand.variable = true; nextBracketPos = filterString.indexOf(">",p); break; + case "(": // Round brackets + operand.multiValuedVariable = true; + nextBracketPos = filterString.indexOf(")",p); + break; case "/": // regexp brackets var rex = /^((?:[^\\\/]|\\.)*)\/(?:\(([mygi]+)\))?/g, rexMatch = rex.exec(filterString.substring(p)); @@ -255,6 +259,8 @@ exports.compileFilter = function(filterString) { currTiddlerTitle = widget && widget.getVariable("currentTiddler"); $tw.utils.each(operation.operators,function(operator) { var operands = [], + multiValueOperands = [], + isMultiValueOperand = [], operatorFunction; if(!operator.operator) { // Use the "title" operator if no operator is specified @@ -269,13 +275,29 @@ exports.compileFilter = function(filterString) { $tw.utils.each(operator.operands,function(operand) { if(operand.indirect) { operand.value = self.getTextReference(operand.text,"",currTiddlerTitle); + operand.multiValue = [operand.value]; } else if(operand.variable) { var varTree = $tw.utils.parseFilterVariable(operand.text); operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || ""; + operand.multiValue = [operand.value]; + } else if(operand.multiValuedVariable) { + var varTree = $tw.utils.parseFilterVariable(operand.text); + var resultList = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source}); + if((resultList.length > 0 && resultList[0] !== undefined) || resultList.length === 0) { + operand.multiValue = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source}) || []; + operand.value = operand.multiValue[0] || ""; + } else { + operand.value = ""; + operand.multiValue = []; + } + operand.isMultiValueOperand = true; } else { operand.value = operand.text; + operand.multiValue = [operand.value]; } operands.push(operand.value); + multiValueOperands.push(operand.multiValue); + isMultiValueOperand.push(!!operand.isMultiValueOperand); }); // Invoke the appropriate filteroperator module @@ -283,6 +305,8 @@ exports.compileFilter = function(filterString) { operator: operator.operator, operand: operands.length > 0 ? operands[0] : undefined, operands: operands, + multiValueOperands: multiValueOperands, + isMultiValueOperand: isMultiValueOperand, prefix: operator.prefix, suffix: operator.suffix, suffixes: operator.suffixes, diff --git a/core/modules/filters/title.js b/core/modules/filters/title.js index 88ac6f132..a3eeb83c8 100644 --- a/core/modules/filters/title.js +++ b/core/modules/filters/title.js @@ -24,7 +24,11 @@ exports.title = function(source,operator,options) { } }); } else { - results.push(operator.operand); + if(operator.isMultiValueOperand[0]) { + Array.prototype.push.apply(results,operator.multiValueOperands[0]); + } else { + results.push(operator.operand); + } } return results; }; diff --git a/core/modules/filters/varlist.js b/core/modules/filters/varlist.js deleted file mode 100644 index 0857da2fe..000000000 --- a/core/modules/filters/varlist.js +++ /dev/null @@ -1,27 +0,0 @@ -/*\ -title: $:/core/modules/filters/varlist.js -type: application/javascript -module-type: filteroperator - -Retrieve the value of a variable as a list - -\*/ -(function(){ - -/*jslint node: true, browser: true */ -/*global $tw: false */ -"use strict"; - -/* -Export our filter function -*/ -exports.varlist = function(source,operator,options) { - var variableInfo = operator.operand && options.widget.getVariableInfo(operator.operand); - if(variableInfo && variableInfo.text !== undefined) { - return options.wiki.makeTiddlerIterator(variableInfo.resultList); - } else { - return []; - } -}; - -})(); diff --git a/editions/prerelease/tiddlers/system/DefaultTiddlers.tid b/editions/prerelease/tiddlers/system/DefaultTiddlers.tid index 0bd696977..38cb8526e 100644 --- a/editions/prerelease/tiddlers/system/DefaultTiddlers.tid +++ b/editions/prerelease/tiddlers/system/DefaultTiddlers.tid @@ -2,6 +2,5 @@ created: 20131127215321439 modified: 20140912135951542 title: $:/DefaultTiddlers +[[Multi-Valued Variables]] [[Let Filter Run Prefix]] -[[varlist Operator]] -[[LetListWidget]] diff --git a/editions/test/tiddlers/tests/data/let-filter-prefix/ResultList.tid b/editions/test/tiddlers/tests/data/let-filter-prefix/ResultList.tid index 4263e565b..594ad4b4b 100644 --- a/editions/test/tiddlers/tests/data/let-filter-prefix/ResultList.tid +++ b/editions/test/tiddlers/tests/data/let-filter-prefix/ResultList.tid @@ -5,7 +5,7 @@ tags: [[$:/tags/wiki-test-spec]] title: Output -<$text text={{{ [all[tiddlers]] :let[[varname]] [varlist[varname]sort[]join[,]] }}}/> +<$text text={{{ [all[tiddlers]] :let[[varname]] [(varname)sort[]join[,]] }}}/> + title: ExpectedResult diff --git a/editions/test/tiddlers/tests/data/let-filter-prefix/ResultListUnnamedVariable.tid b/editions/test/tiddlers/tests/data/let-filter-prefix/ResultListUnnamedVariable.tid index 7f8c8525b..58493f2f4 100644 --- a/editions/test/tiddlers/tests/data/let-filter-prefix/ResultListUnnamedVariable.tid +++ b/editions/test/tiddlers/tests/data/let-filter-prefix/ResultListUnnamedVariable.tid @@ -5,7 +5,7 @@ tags: [[$:/tags/wiki-test-spec]] title: Output -<$text text={{{ [all[tiddlers]] :let[all[]tag[nothing]] [varlist[varname]sort[]join[,]] }}}/> +<$text text={{{ [all[tiddlers]] :let[all[]tag[nothing]] [(varname)sort[]join[,]] }}}/> + title: ExpectedResult diff --git a/editions/test/tiddlers/tests/data/multi-valued-variables/MissingVariable.tid b/editions/test/tiddlers/tests/data/multi-valued-variables/MissingVariable.tid index 30744d844..8481dcb44 100644 --- a/editions/test/tiddlers/tests/data/multi-valued-variables/MissingVariable.tid +++ b/editions/test/tiddlers/tests/data/multi-valued-variables/MissingVariable.tid @@ -1,11 +1,11 @@ title: MultiValuedVariables/MissingVariable -description: Using varlist with a missing variable +description: Using multivalued operands with a missing variable type: text/vnd.tiddlywiki-multiple tags: [[$:/tags/wiki-test-spec]] title: Output -<$text text={{{ [varlist[varname]] }}}/> +<$text text={{{ [(varname)] }}}/> + title: ExpectedResult diff --git a/editions/test/tiddlers/tests/data/multi-valued-variables/MultiValuedFunction.tid b/editions/test/tiddlers/tests/data/multi-valued-variables/MultiValuedFunction.tid index 228c42bf4..15d20731a 100644 --- a/editions/test/tiddlers/tests/data/multi-valued-variables/MultiValuedFunction.tid +++ b/editions/test/tiddlers/tests/data/multi-valued-variables/MultiValuedFunction.tid @@ -8,7 +8,7 @@ title: Output \function myfunc() [all[tiddlers]sort[]] <$let varname=<>> -<$text text={{{ [varlist[varname]] +[join[-]] }}}/> +<$text text={{{ [(varname)] +[join[-]] }}}/> + title: ExpectedResult diff --git a/editions/test/tiddlers/tests/data/multi-valued-variables/MultiValuedOperands.tid b/editions/test/tiddlers/tests/data/multi-valued-variables/MultiValuedOperands.tid new file mode 100644 index 000000000..902dc5699 --- /dev/null +++ b/editions/test/tiddlers/tests/data/multi-valued-variables/MultiValuedOperands.tid @@ -0,0 +1,18 @@ +title: MultiValuedVariables/Operands +description: Multi-valued operands +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +\function myfunc() [all[tiddlers]sort[]] + +<$let varname=<>> +<$text text={{{ [(varname)] +[join[-]] }}}/> + ++ +title: ExpectedResult + +

+$:/core-ExpectedResult-Output +

\ No newline at end of file diff --git a/editions/test/tiddlers/tests/data/multi-valued-variables/Simple.tid b/editions/test/tiddlers/tests/data/multi-valued-variables/Simple.tid index ebaf11901..f52e1e6a1 100644 --- a/editions/test/tiddlers/tests/data/multi-valued-variables/Simple.tid +++ b/editions/test/tiddlers/tests/data/multi-valued-variables/Simple.tid @@ -7,7 +7,7 @@ title: Output <$let varname={{{ [all[tiddlers]sort[]] }}} varname2=<>> -<$text text={{{ [varlist[varname2]] +[join[-]] }}}/> +<$text text={{{ [(varname2)] +[join[-]] }}}/> + title: ExpectedResult diff --git a/editions/tw5.com/tiddlers/filters/syntax/Let Filter Run Prefix.tid b/editions/tw5.com/tiddlers/filters/syntax/Let Filter Run Prefix.tid index 60daba149..d29a0ad90 100644 --- a/editions/tw5.com/tiddlers/filters/syntax/Let Filter Run Prefix.tid +++ b/editions/tw5.com/tiddlers/filters/syntax/Let Filter Run Prefix.tid @@ -17,6 +17,6 @@ type: text/vnd.tiddlywiki The `:let` filter run prefix assigns the title list resulting from previous filter runs to a [[multi-valued variable|Multi-Valued Variable]]. The variable is named with the first result returned by the filter run. -The variable is made available to the remaining [[filter runs|Filter Run]] in the [[filter expression|Filter Expression]]. Only the first item in the result list is returned when the variable is accessed in the usual way (or an empty string if the result list is empty). The special [varlist Operator] is used to access all the items in the result list. +The variable is made available to the remaining [[filter runs|Filter Run]] in the [[filter expression|Filter Expression]]. Only the first item in the result list is returned when the variable is accessed in the usual way (or an empty string if the result list is empty). Using round brackets instead of angle brackets around a variable name as an operand retrieves the complete list of items in the result list. The `:let` filter run prefix always clears the current result list. \ No newline at end of file diff --git a/editions/tw5.com/tiddlers/filters/varlist Operator.tid b/editions/tw5.com/tiddlers/filters/varlist Operator.tid deleted file mode 100644 index 60176b36c..000000000 --- a/editions/tw5.com/tiddlers/filters/varlist Operator.tid +++ /dev/null @@ -1,14 +0,0 @@ -caption: varlist -created: 20250307212252946 -modified: 20250307212252946 -op-input: ignored -op-output: the list items stored in the variable -op-parameter: the name of a variable -op-purpose: retrieve the value of a variable as a list -tags: [[Filter Operators]] [[Selection Constructors]] -title: varlist Operator -type: text/vnd.tiddlywiki - -<<.from-version "5.3.7">> The parameter specifies the name of a variable that has been assigned a list of items by a [[let filter run prefix|Let Filter Run Prefix]]. The operator retrieves all the list items stored in the variable. - -<<.operator-examples "varlist">> diff --git a/editions/tw5.com/tiddlers/system/DefaultTiddlers.tid b/editions/tw5.com/tiddlers/system/DefaultTiddlers.tid index 33be88abd..ab7933bc2 100644 --- a/editions/tw5.com/tiddlers/system/DefaultTiddlers.tid +++ b/editions/tw5.com/tiddlers/system/DefaultTiddlers.tid @@ -3,6 +3,5 @@ modified: 20140912135951542 title: $:/DefaultTiddlers type: text/vnd.tiddlywiki +[[Multi-Valued Variables]] [[Let Filter Run Prefix]] -[[varlist Operator]] -[[LetListWidget]] diff --git a/editions/tw5.com/tiddlers/variables/Multi-Valued Variables.tid b/editions/tw5.com/tiddlers/variables/Multi-Valued Variables.tid index 302f6f084..cd642ef23 100644 --- a/editions/tw5.com/tiddlers/variables/Multi-Valued Variables.tid +++ b/editions/tw5.com/tiddlers/variables/Multi-Valued Variables.tid @@ -3,14 +3,14 @@ created: 20250307212252946 modified: 20250307212252946 tags: Concepts Variables -<<.from-version "5.3.7">> In ordinary usage, [[variables|Variables]] contain a single spinnet of text. With the introduction of multi-valued variables. it is now possible to store a list of multiple values in a single variable. When accessed in the usual way, only the first value is returned, but the [[varlist Operator]] can be used to access all the values. This makes the existence of multi-valued variables largely invisible unless you specifically need to use them. +<<.from-version "5.3.7">> In ordinary usage, [[variables|Variables]] contain a single spinnet of text. With the introduction of multi-valued variables. it is now possible to store a list of multiple values in a single variable. When accessed in the usual way, only the first value is returned, but using round brackets instead of angle brackets around the variable name allows access to the complete list of the values. This makes the existence of multi-valued variables largely invisible unless you specifically need to use them. The <<.wid let>> widget also allows [[multi-valued variables|Multi-Valued Variables]] to be set in one operation, each to the complete list of results obtained from evaluating an attribute. For example: ``` -<$letlist varname={{{ [all[tiddlers]sort[]] }}}> -<$text text={{{ [varlist[varname]] +[join[-]] }}}/> - +<$let varname={{{ [all[tiddlers]sort[]] }}}> +<$text text={{{ [(varname)] +[join[-]] }}}/> + ``` diff --git a/editions/tw5.com/tiddlers/variables/Variables.tid b/editions/tw5.com/tiddlers/variables/Variables.tid index 62fd661e0..53868a40a 100644 --- a/editions/tw5.com/tiddlers/variables/Variables.tid +++ b/editions/tw5.com/tiddlers/variables/Variables.tid @@ -9,7 +9,7 @@ type: text/vnd.tiddlywiki * A <<.def variable>> is a ''snippet of text'' that can be accessed by name * The text is referred to as the variable's <<.def value>> -<<.from-version "5.3.7">> In ordinary usage, variables contain a single spinnet of text. With the introduction of [[Multi-Valued Variables]] it is now possible to store a list of multiple values in a single variable. When accessed in the usual way, only the first value is returned, but the [[varlist Operator]] can be used to access all the values. This makes the existence of multi-valued variables largely invisible unless you specifically need to use them +<<.from-version "5.3.7">> In ordinary usage, variables contain a single spinnet of text. With the introduction of [[Multi-Valued Variables]] it is now possible to store a list of multiple values in a single variable. When accessed in the usual way, only the first value is returned, but using round brackets instead of the usual angle brackets retrieves the complete list of values. This makes the existence of multi-valued variables largely invisible unless you specifically need to use them. Variables are defined by [[widgets|Widgets]]. Several core widgets define variables, the most common being the <<.wlink LetWidget>>, <<.wlink SetWidget>> and <<.wlink ListWidget>> widgets. diff --git a/editions/tw5.com/tiddlers/widgets/LetWidget.tid b/editions/tw5.com/tiddlers/widgets/LetWidget.tid index 5a6e42434..68d6299d8 100644 --- a/editions/tw5.com/tiddlers/widgets/LetWidget.tid +++ b/editions/tw5.com/tiddlers/widgets/LetWidget.tid @@ -23,12 +23,12 @@ Attributes are evaluated in the order they are written. Attributes with the same <<.from-version "5.3.7">> The <<.wid let>> widget also allows [[multi-valued variables|Multi-Valued Variables]] to be set in one operation, each to the complete list of results obtained from evaluating an attribute. -Almost all operations that work with variables only consider the first item in the list. The [[varlist Operator]] gives access to the complete list of results. For example: +Almost all operations that work with variables only consider the first item in the list. Using round brackets instead of angle brackets around the variable name gives access to the complete list of results. For example: ``` -<$letlist varname={{{ [all[tiddlers]sort[]] }}}> -<$text text={{{ [varlist[varname]] +[join[-]] }}}/> - +<$let varname={{{ [all[tiddlers]sort[]] }}}> +<$text text={{{ [(varname)] +[join[-]] }}}/> + ``` ! Examples