From bb5061c6ff5716332542049817f0cd89a7d23657 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Thu, 20 Mar 2025 09:29:15 +0000 Subject: [PATCH] Introduce => as a shortcut syntax for the let filter run prefix Also relax the requirement for a filter run prefix to be followed by an opening square bracket --- core/modules/filters.js | 53 ++++++++++--------- .../data/let-filter-prefix/ShortcutSyntax.tid | 12 +++++ .../Interchangeable Filter Run Prefixes.tid | 1 + .../filters/syntax/Let Filter Run Prefix.tid | 6 +++ .../syntax/Shortcut Filter Run Prefixes.tid | 5 +- 5 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 editions/test/tiddlers/tests/data/let-filter-prefix/ShortcutSyntax.tid diff --git a/core/modules/filters.js b/core/modules/filters.js index 7fb2f4834..2ca232ab2 100644 --- a/core/modules/filters.js +++ b/core/modules/filters.js @@ -148,7 +148,7 @@ exports.parseFilter = function(filterString) { p = 0, // Current position in the filter string match; var whitespaceRegExp = /(\s+)/mg, - operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg; + operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg; while(p < filterString.length) { // Skip any whitespace whitespaceRegExp.lastIndex = p; @@ -159,37 +159,38 @@ exports.parseFilter = function(filterString) { // Match the start of the operation if(p < filterString.length) { operandRegExp.lastIndex = p; - match = operandRegExp.exec(filterString); - if(!match || match.index !== p) { - throw $tw.language.getString("Error/FilterSyntax"); - } var operation = { prefix: "", operators: [] }; - if(match[1]) { - operation.prefix = match[1]; - p = p + operation.prefix.length; - if(match[2]) { - operation.namedPrefix = match[2]; - } - if(match[3]) { - operation.suffixes = []; - $tw.utils.each(match[3].split(":"),function(subsuffix) { - operation.suffixes.push([]); - $tw.utils.each(subsuffix.split(","),function(entry) { - entry = $tw.utils.trim(entry); - if(entry) { - operation.suffixes[operation.suffixes.length -1].push(entry); - } + match = operandRegExp.exec(filterString); + if(match && match.index === p) { + if(match[1]) { + operation.prefix = match[1]; + p = p + operation.prefix.length; + if(match[2]) { + operation.namedPrefix = match[2]; + } + if(match[3]) { + operation.suffixes = []; + $tw.utils.each(match[3].split(":"),function(subsuffix) { + operation.suffixes.push([]); + $tw.utils.each(subsuffix.split(","),function(entry) { + entry = $tw.utils.trim(entry); + if(entry) { + operation.suffixes[operation.suffixes.length -1].push(entry); + } + }); }); - }); + } + } + if(match[4]) { // Opening square bracket + p = parseFilterOperation(operation.operators,filterString,p); + } else { + p = match.index + match[0].length; } - } - if(match[4]) { // Opening square bracket - p = parseFilterOperation(operation.operators,filterString,p); } else { - p = match.index + match[0].length; + p = parseFilterOperation(operation.operators,filterString,p); } if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title operation.operators.push( @@ -346,6 +347,8 @@ exports.compileFilter = function(filterString) { return filterRunPrefixes["and"](operationSubFunction, options); case "~": // This operation is unioned into the result only if the main result so far is empty return filterRunPrefixes["else"](operationSubFunction, options); + case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable + return filterRunPrefixes["let"](operationSubFunction, options); default: if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) { return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options); diff --git a/editions/test/tiddlers/tests/data/let-filter-prefix/ShortcutSyntax.tid b/editions/test/tiddlers/tests/data/let-filter-prefix/ShortcutSyntax.tid new file mode 100644 index 000000000..a7430994c --- /dev/null +++ b/editions/test/tiddlers/tests/data/let-filter-prefix/ShortcutSyntax.tid @@ -0,0 +1,12 @@ +title: LetFilterRunPrefix/Simple +description: Simple usage of "let" filter run prefix +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +<$text text={{{ [[magpie]] =>varname [] +[join[-]] }}}/> ++ +title: ExpectedResult + +

magpie

\ No newline at end of file diff --git a/editions/tw5.com/tiddlers/filters/syntax/Interchangeable Filter Run Prefixes.tid b/editions/tw5.com/tiddlers/filters/syntax/Interchangeable Filter Run Prefixes.tid index 0313f543a..66acfbef7 100644 --- a/editions/tw5.com/tiddlers/filters/syntax/Interchangeable Filter Run Prefixes.tid +++ b/editions/tw5.com/tiddlers/filters/syntax/Interchangeable Filter Run Prefixes.tid @@ -14,6 +14,7 @@ In technical / logical terms: |`-[run]` |`:except[run]` |difference of sets |... AND NOT run | |`~[run]` |`:else[run]` |else |... ELSE run | |`=[run]` |`:all[run]` |union of sets without de-duplication |... OR run | +|`=>[run]` |`:let[run]` |assign results to a variable |... LET run | The input of a run is normally a list of all the non-[[shadow|ShadowTiddlers]] tiddler titles in the wiki (in no particular order).
But the `+` prefix can change this: 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 d29a0ad90..807880713 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 @@ -19,4 +19,10 @@ The `:let` filter run prefix assigns the title list resulting from previous filt 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. +This prefix has an optional [[shortcut syntax|Shortcut Filter Run Prefix]] symbol `=>run`. For example: + +``` +=[] =[] =>myvar +``` + 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/syntax/Shortcut Filter Run Prefixes.tid b/editions/tw5.com/tiddlers/filters/syntax/Shortcut Filter Run Prefixes.tid index fa8bc26e1..224f867bf 100644 --- a/editions/tw5.com/tiddlers/filters/syntax/Shortcut Filter Run Prefixes.tid +++ b/editions/tw5.com/tiddlers/filters/syntax/Shortcut Filter Run Prefixes.tid @@ -9,7 +9,7 @@ Shortcut prefixes are commonly used by advanced users because they are fast to t <$railroad text=""" \start none \end none -(-|:"+"|"-"|"~"|"=") +(-|:"+"|"-"|"~"|"="|"=>") [[run|"Filter Run"]] """/> @@ -23,7 +23,8 @@ If a run has: * the prefix `~`, if the filter output so far is an empty list then the output titles of the run are [[dominantly appended|Dominant Append]] to the filter's output. If the filter output so far is not an empty list then the run is ignored. <<.from-version "5.1.18">> -* the prefix `=`, output titles are appended to the filter's output without de-duplication. <<.from-version "5.1.20">> +* the prefix `=`, output titles are appended to the filter's output without de-duplication. <<.from-version "5.1.20">> +* the prefix `=>`, the input is assigned to the variable named with the output title. <<.from-version "5.3.7">> {{Interchangeable Filter Run Prefixes}} \ No newline at end of file