mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-22 10:54:46 +00:00
Compare commits
60 Commits
fix-browse
...
filter-ins
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09193d49c4 | ||
|
|
356e8e2f23 | ||
|
|
26d9d9fb62 | ||
|
|
c0d9c4f9ec | ||
|
|
4351a3d906 | ||
|
|
728243a66a | ||
|
|
3f733796e5 | ||
|
|
8711726ecd | ||
|
|
6eddffd7c5 | ||
|
|
29a5a1c571 | ||
|
|
83da90d4cd | ||
|
|
6b2b1df9ad | ||
|
|
d995e1a87d | ||
|
|
60165678e4 | ||
|
|
0b03e79339 | ||
|
|
93546c5511 | ||
|
|
e2e14db1f0 | ||
|
|
6c59263070 | ||
|
|
628a2a45e6 | ||
|
|
51d79fc5ac | ||
|
|
b4e48bb2b1 | ||
|
|
210311eccf | ||
|
|
2f767cdb28 | ||
|
|
0a0838e753 | ||
|
|
66196d5c2b | ||
|
|
483522ea09 | ||
|
|
3801e2536c | ||
|
|
77aec1f8f8 | ||
|
|
df529d7d7b | ||
|
|
8dbb41ba2a | ||
|
|
b632b75f70 | ||
|
|
ef92b899ed | ||
|
|
dcb8fa2f86 | ||
|
|
c5894c64b9 | ||
|
|
04ad642be7 | ||
|
|
c8f17511f9 | ||
|
|
845b4ba3b5 | ||
|
|
8ea00a05d3 | ||
|
|
28698690b3 | ||
|
|
3c6ec3f9bb | ||
|
|
3a2c81192e | ||
|
|
d29199ffa8 | ||
|
|
e741816a70 | ||
|
|
002c319518 | ||
|
|
33964d460d | ||
|
|
9b3e61ef10 | ||
|
|
967e882040 | ||
|
|
06dfe365be | ||
|
|
3e1286013f | ||
|
|
1972e8b5f3 | ||
|
|
3cb6712ccb | ||
|
|
8b3fbe3134 | ||
|
|
f6b39d1a40 | ||
|
|
1e10496fd6 | ||
|
|
5226ca1f75 | ||
|
|
037b4aa227 | ||
|
|
ddeb4fd6e6 | ||
|
|
8ff0cb8650 | ||
|
|
27075acbc6 | ||
|
|
d4043fc1f4 |
@@ -107,20 +107,33 @@ fi
|
||||
# /index.html Main site
|
||||
# /external-(version).html External core version of main site
|
||||
# /favicon.ico Favicon for main site
|
||||
# /static.html Static rendering of default tiddlers
|
||||
# /alltiddlers.html Static rendering of all tiddlers
|
||||
# /static/* Static single tiddlers
|
||||
# /static/static.css Static stylesheet
|
||||
# /static/favicon.ico Favicon for static pages
|
||||
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
$TW5_BUILD_MAIN_EDITION \
|
||||
--version \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build favicon static index external-js \
|
||||
--build favicon index external-js \
|
||||
|| exit 1
|
||||
|
||||
# /static.html Static rendering of default tiddlers
|
||||
# /alltiddlers.html Static rendering of all tiddlers
|
||||
# /static/* Static single tiddlers
|
||||
# /static/static.css Static stylesheet
|
||||
# /static/favicon.ico Favicon for static pages
|
||||
|
||||
# Conditionally build static files if $TW5_BUILD_STATIC variable is not set or is set to 0
|
||||
if [ -z "$TW5_BUILD_STATIC" ] || [ "$TW5_BUILD_STATIC" = "0" ]; then
|
||||
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
$TW5_BUILD_MAIN_EDITION \
|
||||
--version \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build static \
|
||||
|| exit 1
|
||||
fi
|
||||
|
||||
# /empty.html Empty
|
||||
# /empty.hta For Internet Explorer
|
||||
# /empty-external-core.html External core empty
|
||||
@@ -190,6 +203,9 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
#
|
||||
######################################################
|
||||
|
||||
# Conditionally build editions if $TW5_BUILD_EDITIONS variable is not set or is set to 0
|
||||
if [ -z "$TW5_BUILD_EDITIONS" ] || [ "$TW5_BUILD_EDITIONS" = "0" ]; then
|
||||
|
||||
# /editions/xlsx-utils/index.html xlsx-utils edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/xlsx-utils \
|
||||
@@ -254,12 +270,18 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
fi
|
||||
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Plugin demos
|
||||
#
|
||||
######################################################
|
||||
|
||||
# Conditionally build plugin demos if $TW5_BUILD_PLUGIN_DEMOS variable is not set
|
||||
if [ -z "$TW5_BUILD_PLUGIN_DEMOS" ] || [ "$TW5_BUILD_PLUGIN_DEMOS" = "0" ]; then
|
||||
|
||||
# /plugins/tiddlywiki/innerwiki/index.html Demo wiki with Innerwiki plugin
|
||||
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
@@ -364,12 +386,17 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/geospatial/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
fi
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Language editions
|
||||
#
|
||||
######################################################
|
||||
|
||||
# Conditionally build language editions if $TW5_BUILD_LANGUAGE_DEMOS variable is not set
|
||||
if [ -z "$TW5_BUILD_LANGUAGE_DEMOS" ] || [ "$TW5_BUILD_LANGUAGE_DEMOS" = "0" ]; then
|
||||
|
||||
# Delete any existing static content
|
||||
|
||||
rm -rf $TW5_BUILD_OUTPUT/languages/de-AT/static/*
|
||||
@@ -453,12 +480,17 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
--build empty index \
|
||||
|| exit 1
|
||||
|
||||
fi
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Plugin library
|
||||
#
|
||||
######################################################
|
||||
|
||||
# Conditionally build plugin library if $TW5_BUILD_PLUGIN_LIBRARY variable is not set
|
||||
if [ -z "$TW5_BUILD_PLUGIN_LIBRARY" ] || [ "$TW5_BUILD_PLUGIN_LIBRARY" = "0" ]; then
|
||||
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/pluginlibrary \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
@@ -466,6 +498,8 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
--build library\
|
||||
|| exit 1
|
||||
|
||||
fi
|
||||
|
||||
# Delete the temporary build tiddler
|
||||
|
||||
rm $TW5_BUILD_OUTPUT/build.tid || exit 1
|
||||
|
||||
@@ -2732,14 +2732,15 @@ $tw.hooks.removeHook = function(hookName,definition) {
|
||||
/*
|
||||
Invoke the hook by key
|
||||
*/
|
||||
$tw.hooks.invokeHook = function(hookName /*, value,... */) {
|
||||
var args = Array.prototype.slice.call(arguments,1);
|
||||
if($tw.utils.hop($tw.hooks.names,hookName)) {
|
||||
$tw.hooks.invokeHook = function(hookName, firstArgument /*, value,... */) {
|
||||
if(Object.prototype.hasOwnProperty.call($tw.hooks.names,hookName)) {
|
||||
var args = Array.prototype.slice.call(arguments,1);
|
||||
for(var i = 0; i < $tw.hooks.names[hookName].length; i++) {
|
||||
args[0] = $tw.hooks.names[hookName][i].apply(null,args);
|
||||
}
|
||||
return args[0];
|
||||
}
|
||||
return args[0];
|
||||
return firstArgument;
|
||||
};
|
||||
|
||||
/////////////////////////// Main boot function to decrypt tiddlers and then startup
|
||||
|
||||
@@ -3,7 +3,9 @@ title: $:/language/Search/
|
||||
DefaultResults/Caption: List
|
||||
Filter/Caption: Filter
|
||||
Filter/Hint: Search via a [[filter expression|https://tiddlywiki.com/static/Filters.html]]
|
||||
Filter/Placeholder: Filter expression
|
||||
Filter/Matches: //<small><<resultCount>> matches</small>//
|
||||
Filter/FilterResults/Results/Caption: Results
|
||||
Matches: //<small><<resultCount>> matches</small>//
|
||||
Matches/All: All matches:
|
||||
Matches/NoMatch: //No match//
|
||||
|
||||
@@ -220,13 +220,25 @@ exports.filterTiddlers = function(filterString,widget,source) {
|
||||
Compile a filter into a function with the signature fn(source,widget) where:
|
||||
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
||||
widget: an optional widget node for retrieving the current tiddler etc.
|
||||
|
||||
Parameters:
|
||||
filterString: the filter string to compile
|
||||
options: includes:
|
||||
|
||||
wrappers: a hashmap of wrapper functions to apply to the compiled filter function
|
||||
*/
|
||||
exports.compileFilter = function(filterString) {
|
||||
exports.compileFilter = function(filterString,options) {
|
||||
options = options || {};
|
||||
var self = this;
|
||||
var wrappers = options.wrappers || {};
|
||||
// Invoke the hook to allow the filter to be inspected
|
||||
wrappers = $tw.hooks.invokeHook("th-filter-evaluation",filterString,wrappers) || wrappers;
|
||||
// Get the result from the cache if we can
|
||||
if(!this.filterCache) {
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
if(this.filterCache[filterString] !== undefined) {
|
||||
if(this.filterCache[filterString] !== undefined && !wrappers.prefix && !wrappers.operation && !wrappers.operator && !wrappers.start && !wrappers.done) {
|
||||
return this.filterCache[filterString];
|
||||
}
|
||||
var filterParseTree;
|
||||
@@ -235,7 +247,14 @@ exports.compileFilter = function(filterString) {
|
||||
} catch(e) {
|
||||
// We do not cache this result, so it adjusts along with localization changes
|
||||
return function(source,widget) {
|
||||
return [$tw.language.getString("Error/Filter") + ": " + e];
|
||||
if(wrappers.start) {
|
||||
wrappers.start(source,widget);
|
||||
}
|
||||
var resultsArray = [$tw.language.getString("Error/Filter") + ": " + e];
|
||||
if(wrappers.done) {
|
||||
wrappers.done(resultsArray);
|
||||
}
|
||||
return resultsArray;
|
||||
};
|
||||
}
|
||||
// Get the hashmap of filter operator functions
|
||||
@@ -249,52 +268,64 @@ exports.compileFilter = function(filterString) {
|
||||
var operationSubFunction = function(source,widget) {
|
||||
var accumulator = source,
|
||||
results = [],
|
||||
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operands = [],
|
||||
operatorFunction;
|
||||
if(!operator.operator) {
|
||||
// Use the "title" operator if no operator is specified
|
||||
operatorFunction = filterOperators.title;
|
||||
} else if(!filterOperators[operator.operator]) {
|
||||
// Unknown operators treated as "[unknown]" - at run time we can distinguish between a custom operator and falling back to the default "field" operator
|
||||
operatorFunction = filterOperators["[unknown]"];
|
||||
} else {
|
||||
// Use the operator function
|
||||
operatorFunction = filterOperators[operator.operator];
|
||||
}
|
||||
$tw.utils.each(operator.operands,function(operand) {
|
||||
if(operand.indirect) {
|
||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||
} else if(operand.variable) {
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
|
||||
} else {
|
||||
operand.value = operand.text;
|
||||
}
|
||||
operands.push(operand.value);
|
||||
});
|
||||
|
||||
// Invoke the appropriate filteroperator module
|
||||
results = operatorFunction(accumulator,{
|
||||
operator: operator.operator,
|
||||
operand: operands.length > 0 ? operands[0] : undefined,
|
||||
operands: operands,
|
||||
prefix: operator.prefix,
|
||||
suffix: operator.suffix,
|
||||
suffixes: operator.suffixes,
|
||||
regexp: operator.regexp
|
||||
},{
|
||||
wiki: self,
|
||||
widget: widget
|
||||
currTiddlerTitle = widget && widget.getVariable("currentTiddler"),
|
||||
handleOperation = function() {
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operands = [],
|
||||
operatorName,operatorFunction;
|
||||
if(!operator.operator) {
|
||||
// Use the "title" operator if no operator is specified
|
||||
operatorName = "title";
|
||||
} else if(!filterOperators[operator.operator]) {
|
||||
// Unknown operators treated as "[unknown]" - at run time we can distinguish between a custom operator and falling back to the default "field" operator
|
||||
operatorName = "[unknown]";
|
||||
} else {
|
||||
// Use the operator function
|
||||
operatorName = operator.operator;
|
||||
}
|
||||
operatorFunction = filterOperators[operatorName];
|
||||
$tw.utils.each(operator.operands,function(operand) {
|
||||
if(operand.indirect) {
|
||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||
} else if(operand.variable) {
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
|
||||
} else {
|
||||
operand.value = operand.text;
|
||||
}
|
||||
operands.push(operand.value);
|
||||
});
|
||||
if($tw.utils.isArray(results)) {
|
||||
accumulator = self.makeTiddlerIterator(results);
|
||||
} else {
|
||||
accumulator = results;
|
||||
}
|
||||
});
|
||||
if($tw.utils.isArray(results)) {
|
||||
// Wrap the filter operator module if required
|
||||
if(wrappers.operator) {
|
||||
operatorFunction = wrappers.operator.bind(self,operatorFunction);
|
||||
}
|
||||
// Invoke the appropriate filteroperator module
|
||||
results = operatorFunction(accumulator,{
|
||||
parseTree: operator,
|
||||
operator: operator.operator,
|
||||
operatorName: operatorName,
|
||||
operand: operands.length > 0 ? operands[0] : undefined,
|
||||
operands: operands,
|
||||
prefix: operator.prefix,
|
||||
suffix: operator.suffix,
|
||||
suffixes: operator.suffixes,
|
||||
regexp: operator.regexp
|
||||
},{
|
||||
wiki: self,
|
||||
widget: widget
|
||||
});
|
||||
if($tw.utils.isArray(results)) {
|
||||
accumulator = self.makeTiddlerIterator(results);
|
||||
} else {
|
||||
accumulator = results;
|
||||
}
|
||||
});
|
||||
};
|
||||
if(wrappers.operation) {
|
||||
handleOperation = wrappers.operation.bind(self,handleOperation,operation);
|
||||
}
|
||||
handleOperation();
|
||||
if($tw.utils.isArray(results)) {
|
||||
return results;
|
||||
} else {
|
||||
var resultArray = [];
|
||||
@@ -307,27 +338,45 @@ exports.compileFilter = function(filterString) {
|
||||
var filterRunPrefixes = self.getFilterRunPrefixes();
|
||||
// Wrap the operator functions in a wrapper function that depends on the prefix
|
||||
operationFunctions.push((function() {
|
||||
var options = {wiki: self, suffixes: operation.suffixes || []};
|
||||
var prefixName;
|
||||
switch(operation.prefix || "") {
|
||||
case "": // No prefix means that the operation is unioned into the result
|
||||
return filterRunPrefixes["or"](operationSubFunction, options);
|
||||
prefixName = "or";
|
||||
break;
|
||||
case "=": // The results of the operation are pushed into the result without deduplication
|
||||
return filterRunPrefixes["all"](operationSubFunction, options);
|
||||
prefixName = "all";
|
||||
break;
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return filterRunPrefixes["except"](operationSubFunction, options);
|
||||
prefixName = "except";
|
||||
break;
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||
prefixName = "and";
|
||||
break;
|
||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||
default:
|
||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||
} else {
|
||||
return function(results,source,widget) {
|
||||
results.clear();
|
||||
results.push($tw.language.getString("Error/FilterRunPrefix"));
|
||||
};
|
||||
}
|
||||
prefixName = "else";
|
||||
break;
|
||||
default:
|
||||
prefixName = operation.namedPrefix;
|
||||
break;
|
||||
}
|
||||
if(prefixName && filterRunPrefixes[prefixName]) {
|
||||
var options = {
|
||||
wiki: self,
|
||||
suffixes: operation.suffixes || [],
|
||||
prefixName: prefixName,
|
||||
prefix: operation.prefix
|
||||
},
|
||||
filterRunPrefixFunction = filterRunPrefixes[prefixName];
|
||||
// Wrap the filter operator module if required
|
||||
if(wrappers.prefix) {
|
||||
filterRunPrefixFunction = wrappers.prefix.bind(self,filterRunPrefixFunction);
|
||||
}
|
||||
return filterRunPrefixFunction(operationSubFunction,options);
|
||||
} else {
|
||||
return function(results,source,widget) {
|
||||
results.clear();
|
||||
results.push($tw.language.getString("Error/FilterRunPrefix"));
|
||||
};
|
||||
}
|
||||
})());
|
||||
});
|
||||
@@ -341,6 +390,9 @@ exports.compileFilter = function(filterString) {
|
||||
if(!widget) {
|
||||
widget = $tw.rootWidget;
|
||||
}
|
||||
if(wrappers.start) {
|
||||
wrappers.start(source,widget);
|
||||
}
|
||||
var results = new $tw.utils.LinkedList();
|
||||
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||
@@ -351,7 +403,11 @@ exports.compileFilter = function(filterString) {
|
||||
results.push("/**-- Excessive filter recursion --**/");
|
||||
}
|
||||
self.filterRecursionCount = self.filterRecursionCount - 1;
|
||||
return results.toArray();
|
||||
var resultsArray = results.toArray();
|
||||
if(wrappers.done) {
|
||||
wrappers.done(resultsArray);
|
||||
}
|
||||
return resultsArray;
|
||||
});
|
||||
if(this.filterCacheCount >= 2000) {
|
||||
// To prevent memory leak, we maintain an upper limit for cache size.
|
||||
@@ -360,7 +416,9 @@ exports.compileFilter = function(filterString) {
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
this.filterCache[filterString] = fnMeasured;
|
||||
this.filterCacheCount++;
|
||||
if(!wrappers.prefix && !wrappers.operator) {
|
||||
this.filterCache[filterString] = fnMeasured;
|
||||
this.filterCacheCount++;
|
||||
}
|
||||
return fnMeasured;
|
||||
};
|
||||
|
||||
@@ -34,39 +34,11 @@ caption: {{$:/language/Search/Filter/Caption}}
|
||||
</$list>
|
||||
\end
|
||||
|
||||
\procedure input-accept-actions()
|
||||
\whitespace trim
|
||||
<$list filter="[{$:/config/Search/NavigateOnEnter/enable}match[yes]]">
|
||||
<$list-empty>
|
||||
<$list filter="[<tiddler>get[text]!is[missing]] :else[<tiddler>get[text]is[shadow]]">
|
||||
<$action-navigate $to={{{ [<tiddler>get[text]] }}}/>
|
||||
</$list>
|
||||
<$/list-empty>
|
||||
<$action-navigate $to={{{ [<tiddler>get[text]] }}}/>
|
||||
</$list>
|
||||
\end
|
||||
|
||||
\procedure input-accept-variant-actions()
|
||||
\whitespace trim
|
||||
<$list filter="[{$:/config/Search/NavigateOnEnter/enable}match[yes]]">
|
||||
<$list-empty>
|
||||
<$list filter="[<tiddler>get[text]!is[missing]] :else[<tiddler>get[text]is[shadow]]">
|
||||
<$list filter="[<__tiddler__>get[text]minlength[1]]">
|
||||
<$action-sendmessage $message="tm-edit-tiddler" $param={{{ [<tiddler>get[text]] }}}/>
|
||||
</$list>
|
||||
</$list>
|
||||
</$list-empty>
|
||||
<$list filter="[<tiddler>get[text]minlength[1]]">
|
||||
<$action-sendmessage $message="tm-edit-tiddler" $param={{{ [<tiddler>get[text]] }}}/>
|
||||
</$list>
|
||||
</$list>
|
||||
\end
|
||||
|
||||
\whitespace trim
|
||||
|
||||
<<lingo Filter/Hint>>
|
||||
|
||||
<div class="tc-search tc-advanced-search">
|
||||
<div class="tc-search tc-advanced-search tc-edit-max-width">
|
||||
<$keyboard key="((input-tab-right))" actions=<<set-next-input-tab>> class="tc-small-gap-right">
|
||||
<$keyboard key="((input-tab-left))" actions=<<set-previous-input-tab>>>
|
||||
<$transclude $variable="keyboard-driven-input"
|
||||
@@ -75,13 +47,16 @@ caption: {{$:/language/Search/Filter/Caption}}
|
||||
refreshTitle="$:/temp/advancedsearch/refresh"
|
||||
selectionStateTitle="$:/temp/advancedsearch/selected-item"
|
||||
type="search"
|
||||
tag="input"
|
||||
tag="textarea"
|
||||
focus={{$:/config/Search/AutoFocus}}
|
||||
configTiddlerFilter="[[$:/temp/advancedsearch]]"
|
||||
firstSearchFilterField="text"
|
||||
inputAcceptActions=<<input-accept-actions>>
|
||||
inputAcceptVariantActions=<<input-accept-variant-actions>>
|
||||
inputAcceptActions=""
|
||||
inputAcceptVariantActions=""
|
||||
inputCancelActions=<<cancel-search-actions>>
|
||||
minHeight="2em"
|
||||
autoHeight="yes"
|
||||
placeholder={{$:/language/Search/Filter/Placeholder}}
|
||||
/>
|
||||
</$keyboard>
|
||||
</$keyboard>
|
||||
@@ -90,13 +65,18 @@ caption: {{$:/language/Search/Filter/Caption}}
|
||||
</$list>
|
||||
</div>
|
||||
|
||||
<$reveal state="$:/temp/advancedsearch" type="nomatch" text="" tag="div" class="tc-search-results">
|
||||
<$set name="resultCount" value="<$count filter={{$:/temp/advancedsearch}}/>">
|
||||
<p><<lingo Filter/Matches>></p>
|
||||
<$list filter={{$:/temp/advancedsearch}}>
|
||||
<span class={{{[<currentTiddler>addsuffix[-primaryList]] -[[$:/temp/advancedsearch/selected-item]get[text]] :and[then[]else[tc-list-item-selected]] }}}>
|
||||
<$transclude tiddler="$:/core/ui/ListItemTemplate"/>
|
||||
</span>
|
||||
</$list>
|
||||
</$set>
|
||||
</$reveal>
|
||||
<%if [{$:/temp/advancedsearch}trim[]!match[]] %>
|
||||
<div class="tc-search-results">
|
||||
<%if [all[shadows+tiddlers]tag[$:/tags/AdvancedSearch/FilterResults]!has[draft.of]count[]compare:number:gt[1]] %>
|
||||
<$macrocall
|
||||
$name="tabs"
|
||||
tabsList="[all[shadows+tiddlers]tag[$:/tags/AdvancedSearch/FilterResults]!has[draft.of]]"
|
||||
default="$:/core/ui/AdvancedSearch/Filter/FilterResults/Results"
|
||||
/>
|
||||
<%else%>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/AdvancedSearch/FilterResults]!has[draft.of]]">
|
||||
<$transclude/>
|
||||
</$list>
|
||||
<%endif%>
|
||||
</div>
|
||||
<%endif%>
|
||||
|
||||
13
core/ui/AdvancedSearch/FilterResults/Results.tid
Normal file
13
core/ui/AdvancedSearch/FilterResults/Results.tid
Normal file
@@ -0,0 +1,13 @@
|
||||
title: $:/core/ui/AdvancedSearch/Filter/FilterResults/Results
|
||||
tags: $:/tags/AdvancedSearch/FilterResults
|
||||
caption: {{$:/language/Search/Filter/FilterResults/Results/Caption}}
|
||||
|
||||
\procedure lingo-base() $:/language/Search/
|
||||
<$set name="resultCount" value="<$count filter={{$:/temp/advancedsearch}}/>">
|
||||
<p><<lingo Filter/Matches>></p>
|
||||
<$list filter={{$:/temp/advancedsearch}}>
|
||||
<span class={{{[<currentTiddler>addsuffix[-primaryList]] -[[$:/temp/advancedsearch/selected-item]get[text]] :and[then[]else[tc-list-item-selected]] }}}>
|
||||
<$transclude tiddler="$:/core/ui/ListItemTemplate"/>
|
||||
</span>
|
||||
</$list>
|
||||
</$set>
|
||||
@@ -2,11 +2,8 @@ created: 20131127215321439
|
||||
modified: 20140912135951542
|
||||
title: $:/DefaultTiddlers
|
||||
|
||||
[[TiddlyWiki Pre-release]]
|
||||
HelloThere
|
||||
[[Quick Start]]
|
||||
[[Find Out More]]
|
||||
[[TiddlyWiki on the Web]]
|
||||
[[Testimonials and Reviews]]
|
||||
GettingStarted
|
||||
Community
|
||||
[[$:/plugins/tiddlywiki/internals]]
|
||||
[[$:/AdvancedSearch]]
|
||||
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator]]
|
||||
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/InspectFilterMacro]]
|
||||
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectfiltermacro/examples]]
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"description": "TiddlyWiki core tests",
|
||||
"plugins": [
|
||||
"tiddlywiki/jasmine",
|
||||
"tiddlywiki/geospatial"
|
||||
"tiddlywiki/geospatial",
|
||||
"tiddlywiki/internals"
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
|
||||
@@ -3,10 +3,8 @@ modified: 20140912135951542
|
||||
title: $:/DefaultTiddlers
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
HelloThere
|
||||
[[Quick Start]]
|
||||
[[Find Out More]]
|
||||
[[TiddlyWiki on the Web]]
|
||||
[[Testimonials and Reviews]]
|
||||
GettingStarted
|
||||
Community
|
||||
[[$:/plugins/tiddlywiki/internals]]
|
||||
[[$:/AdvancedSearch]]
|
||||
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator]]
|
||||
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/InspectFilterMacro]]
|
||||
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectfiltermacro/examples]]
|
||||
|
||||
13
plugins/tiddlywiki/internals/docs.tid
Normal file
13
plugins/tiddlywiki/internals/docs.tid
Normal file
@@ -0,0 +1,13 @@
|
||||
title: $:/plugins/tiddlywiki/internals/docs
|
||||
|
||||
!! `<<inspect-filter>>` Procedure
|
||||
|
||||
{{$:/plugins/tiddlywiki/internals/filterinspection/docs/InspectFilterMacro}}
|
||||
|
||||
!!! `<<inspect-filter>>` Procedure Examples
|
||||
|
||||
{{$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectfiltermacro/examples}}
|
||||
|
||||
!! `inspect` Operator
|
||||
|
||||
{{$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator}}
|
||||
@@ -0,0 +1,8 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/InspectResultsTab
|
||||
tags: $:/tags/AdvancedSearch/FilterResults
|
||||
caption: Inspect
|
||||
list-after: $:/core/ui/AdvancedSearch/Filter/FilterResults/Results
|
||||
|
||||
Filter evaluation trace:
|
||||
|
||||
<$transclude $variable="inspect-filter" filter={{$:/temp/advancedsearch}} />
|
||||
@@ -0,0 +1,44 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/ObserveResultsTab
|
||||
tags: $:/tags/AdvancedSearch/FilterResults
|
||||
caption: Observe
|
||||
list-after: $:/plugins/tiddlywiki/internals/filterinspection/InspectResultsTab
|
||||
|
||||
Log traces of this filter expression in the background. A trace will be generated every time the filter is evaluated, regardless of the context. The trace is only saved if the results are different from previous traces.
|
||||
|
||||
<$checkbox tiddler="$:/config/FilterObservationionEnabled" field="text" checked="yes" unchecked="no" default="no">
|
||||
Enable background filter observation
|
||||
</$checkbox>
|
||||
|
||||
|
||||
<$button>
|
||||
<%if [all[shadows+tiddlers]tag[$:/tags/InspectableFilter]get[text]match{$:/temp/advancedsearch}count[]match[0]] %>
|
||||
<$action-createtiddler $basetitle="$:/config/inspectable-filters/filter" tags="$:/tags/InspectableFilter" type="text/plain" text={{$:/temp/advancedsearch}}/>
|
||||
<%endif%>
|
||||
Enable logging for this filter
|
||||
</$button>
|
||||
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/InspectableFilter]!has[draft.of]sort[]]" variable="inspectableFilter">
|
||||
<div class="tc-box tc-inspectable-filter-box">
|
||||
<div class="tc-box-header">
|
||||
<$text text={{{ [<inspectableFilter>get[text]] }}}/> <$link to=<<inspectableFilter>>>{{$:/core/images/open-window}}</$link>
|
||||
</div>
|
||||
<div class="tc-box-content">
|
||||
<ol>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/FilterInspectionOutput]!has[draft.of]!sort[modified]] :filter[<inspectableFilter>get[text]match{!!filter}]" variable="inspectionOutput">
|
||||
<$let transclusion=<<inspectionOutput>>>
|
||||
<li>
|
||||
<div class="tc-box tc-inspectable-filter-trace-box">
|
||||
<div class="tc-box-header">
|
||||
<$text text={{{ [<inspectionOutput>get[modified]format:date[DDth mmm YYYY 0hh:0mm:0ss]] }}}/><$link to=<<inspectionOutput>>>{{$:/core/images/open-window}}</$link>
|
||||
</div>
|
||||
<div class="tc-box-content">
|
||||
<$transclude $variable="inspect-filter-output-unframed" jsonOutput={{{ [<inspectionOutput>get[text]] }}} />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</$let>
|
||||
</$list>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</$list>
|
||||
@@ -0,0 +1,17 @@
|
||||
caption: inspect-filter
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/docs/InspectFilterMacro
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
The <<.def inspect-filter>> procedure displays a schematic representation of the filter evaluation process, including the input, output and intermediate results of evaluating the specified filter. It is based on the [[inspect operator|$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator]].
|
||||
|
||||
By default the tabs are arranged horizontally above the content. To get vertical tabs, set the `orientation` parameter to `vertical`. This is useful for narrow windows or when the content is too wide to fit in a horizontal tab layout.
|
||||
|
||||
!! Parameters
|
||||
|
||||
;filter
|
||||
: The filter to be inspected
|
||||
;inputFilter
|
||||
: Optionally, a filter defining the input titles for the filter to be inspected, defaulting to `[all[tiddlers]]`
|
||||
;orientation
|
||||
: Optionally, the orientation of the schematic representation, defaulting to `horizontal`. Set to `vertical` to display the tabs vertically
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
caption: inspect
|
||||
tags: [[Filter Operators]]
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
The ''inspect'' operator evaluates a filter with the specified input titles and returns a JSON object containing the input, output and intermediate results of evaluating the specified filter.
|
||||
|
||||
|Operator Purpose |Inspect the evaluation of a filter to aid debugging |
|
||||
|Operator Input |A selection of titles |
|
||||
|Operator Output |A JSON object containing the input, output and intermediate results of evaluating the specified filter |
|
||||
|Operator Parameter |The filter to be inspected |
|
||||
|
||||
The output JSON object contains the following properties:
|
||||
|
||||
* `input`: the input titles passed to the filter
|
||||
* `inputFilter`: the filter being inspected
|
||||
* `output`: the output titles resulting from evaluating the filter
|
||||
* `evaluationTime`: the time taken to evaluate the filter, in milliseconds
|
||||
* `runs`: an array of objects, each of which represents a single run of the filter. Each object contains the following properties:
|
||||
** `prefixName`: the name of the prefix operator that was used in this run. Shortcut prefixes like `+` and `-` are expanded to their full names, e.g. `and` and `except`
|
||||
** `input`: the input titles passed to the prefix operator
|
||||
** `operations`: an array of objects, each of which represents the evaluation of a single operation that was performed in this run. Each object contains the following properties:
|
||||
*** `operators`: an array of objects, each of which represents a single operator that was used in this run. Each object contains the following properties:
|
||||
**** `operatorName`: the name of the operator
|
||||
**** `operands`: an array of string operands passed to the operator
|
||||
**** `input`: the input titles passed to the operator
|
||||
**** `output`: the output titles resulting from evaluating the operator
|
||||
@@ -0,0 +1,38 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/docs/inspectfiltermacro/examples
|
||||
tags: [[Macro Examples]]
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
\procedure .example(n,eg,egvar)
|
||||
<$let eg={{{ [<egvar>!is[blank]getvariable[]] :else[<eg>] }}}>
|
||||
<div class="doc-example">
|
||||
<$macrocall $name="copy-to-clipboard-above-right" src=<<eg>>/>
|
||||
<$codeblock code=<<eg>>/>
|
||||
<$list filter=`[title<.state-prefix>addsuffix{!!title}addsuffix[/]addsuffix[$(n)$]]` variable=".state">
|
||||
<$reveal state=<<.state>> type="nomatch" text="show">
|
||||
<dl>
|
||||
<dd><$button set=<<.state>> setTo="show">Try it</$button></dd>
|
||||
</dl>
|
||||
</$reveal>
|
||||
<$reveal state=<<.state>> type="match" text="show">
|
||||
<dl>
|
||||
<dd><$button set=<<.state>> setTo="">Hide</$button></dd>
|
||||
</dl>
|
||||
<blockquote class="doc-example-result">
|
||||
<$transclude $variable="eg" $mode="block"/>
|
||||
</blockquote>
|
||||
</$reveal>
|
||||
</$list>
|
||||
</div>
|
||||
</$let>
|
||||
\end .example
|
||||
|
||||
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="1 2 3" inputFilter="[all[tiddlers]]"/>"""/>
|
||||
|
||||
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="1 2 3" inputFilter="[all[tiddlers]]" orientation="vertical"/>"""/>
|
||||
|
||||
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="[title<currentTiddler>] [{$:/palette}length[]] [[marker]]" inputFilter="[all[tiddlers]]"/>"""/>
|
||||
|
||||
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="[all[shadows+tiddlers]tag[$:/tags/MenuBar]!has[draft.of]] -[all[tiddlers+shadows]tag[$:/tags/TopLeftBarlimit[1]then[]else[$:/plugins/tiddlywiki/menubar/items/topleftbar]]" inputFilter="[all[tiddlers]]"/>
|
||||
"""/>
|
||||
|
||||
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="[tags[]prefix[$:/]] :sort[length[]add[1]] +[first[2]tagging[]]" inputFilter="[all[tiddlers]]"/>"""/>
|
||||
@@ -0,0 +1,5 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/InspectFilterProcedures/Filters/SlowFilter
|
||||
tags: $:/tags/Filter
|
||||
filter: [all[tiddlers+shadows]limit[500]] :filter[<currentTiddler>length[]reverse[]multiply[3.14]]
|
||||
description: [Internals Plugin] A filter that takes a long time to process
|
||||
|
||||
214
plugins/tiddlywiki/internals/filterinspection/inspect-filter.tid
Normal file
214
plugins/tiddlywiki/internals/filterinspection/inspect-filter.tid
Normal file
@@ -0,0 +1,214 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/InspectFilterProcedures
|
||||
tags: $:/tags/Global
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure inspect-list(jsonList)
|
||||
<$let
|
||||
transclusion={{{ [<jsonList>indexes[]count[]addprefix[-list-]] }}}
|
||||
state=<<qualify "$:/temp/filter-inspector/list">>
|
||||
stateMaxRows={{{ [<state>addsuffix[max-rows]] }}}
|
||||
maxRows={{{ [<stateMaxRows>get[text]!match[]else[10]] }}}
|
||||
stateScroll={{{ [<state>addsuffix[scroll]] }}}
|
||||
>
|
||||
<$text text=<<stateScroll>>/>
|
||||
<$scrollable class="tc-box-content-list-scollable" bind=<<stateScroll>>>
|
||||
<div class="tc-box-content-list">
|
||||
<$list filter="[<jsonList>jsonindexes[]nsort[]limit<maxRows>]" variable="indexList">
|
||||
<$list-template>
|
||||
<div class="tc-box-content-list-item">
|
||||
<$slot $name="list-item"/>
|
||||
</div>
|
||||
</$list-template>
|
||||
<$list-empty>
|
||||
<div class="tc-box-content-list-empty">
|
||||
(No items)
|
||||
</div>
|
||||
</$list-empty>
|
||||
</$list>
|
||||
<%if [<jsonList>jsonindexes[]count[]compare:number:gt<maxRows>] %>
|
||||
<div class="tc-box-content-list-more">
|
||||
<$button class="tc-btn-invisible tc-box-content-full-width-button" style.fill="inherit">
|
||||
<$action-setfield $tiddler=<<stateMaxRows>> text={{{ [<maxRows>add[10]] }}}/>
|
||||
{{$:/core/images/chevron-down}}
|
||||
<$text text="more"/>
|
||||
</$button>
|
||||
</div>
|
||||
<%endif%>
|
||||
</div>
|
||||
</$scrollable>
|
||||
\end inspect-list
|
||||
|
||||
\procedure inspect-foldable-text-list(jsonList,class:"tc-box")
|
||||
<$let
|
||||
transclusion={{{ [[link-list-]addsuffix<class>] }}}
|
||||
>
|
||||
<div class=<<class>>>
|
||||
<$let
|
||||
state=<<qualify "$:/temp/filter-inspector/list">>
|
||||
stateFolded={{{ [<state>addsuffix[folded]] }}}
|
||||
folded={{{ [<stateFolded>get[text]else[no]match[yes]] }}}
|
||||
>
|
||||
<div class="tc-box-header">
|
||||
<$button class="tc-btn-invisible tc-box-content-full-width-button" style.fill="inherit">
|
||||
<%if [<folded>match[yes]] %>
|
||||
<$action-setfield $tiddler=<<stateFolded>> text="no"/>
|
||||
<%else%>
|
||||
<$action-setfield $tiddler=<<stateFolded>> text="yes"/>
|
||||
<%endif%>
|
||||
<$text text={{{ [<jsonList>jsonindexes[]count[]] }}}/>
|
||||
{{$:/core/images/right-arrow}}
|
||||
</$button>
|
||||
</div>
|
||||
<%if [<folded>!match[yes]] %>
|
||||
<div class="tc-box-content">
|
||||
<$transclude $variable="inspect-list" jsonList=<<jsonList>>>
|
||||
<$fill $name="list-item">
|
||||
<$text text={{{ [<jsonList>jsonget<indexList>] }}} />
|
||||
</$fill>
|
||||
</$transclude>
|
||||
</div>
|
||||
<%endif%>
|
||||
</$let>
|
||||
</div>
|
||||
</$let>
|
||||
\end inspect-foldable-text-list
|
||||
|
||||
\procedure inspect-operator(jsonOperator)
|
||||
<div class="tc-box tc-inspect-operator-box">
|
||||
<div class="tc-box-header">
|
||||
<span class="">
|
||||
<$text text={{{ [<jsonOperator>jsonget[prefix]] }}} />
|
||||
<$text text={{{ [<jsonOperator>jsonget[operatorName]] }}} />
|
||||
</span>
|
||||
<%if [<jsonOperator>jsonindexes[suffixes]length[]compare:number:gt[0]] %>
|
||||
<$list filter="[<jsonOperator>jsonindexes[suffixes]nsort[]]" variable="indexSuffix">
|
||||
<span class="tc-pill">
|
||||
:<$text text={{{ [<jsonOperator>jsonget[suffixes],<indexSuffix>] }}} />
|
||||
</span>
|
||||
</$list>
|
||||
<%endif%>
|
||||
<$list filter="[<jsonOperator>jsonindexes[operands]nsort[]]" variable="indexOperand">
|
||||
<div class="tc-split-pill">
|
||||
<div class="tc-split-pill-top">
|
||||
<%if [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[variable]match[true]] %>
|
||||
<$text text="<"/><$text text={{{ [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[text]] }}}/><$text text=">"/>
|
||||
<%elseif [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[indirect]match[true]] %>
|
||||
<$text text="{"/><$text text={{{ [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[text]] }}}/><$text text="}"/>
|
||||
<%else%>
|
||||
<$text text="["/><$text text={{{ [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[text]] }}}/><$text text="]"/>
|
||||
<%endif%>
|
||||
</div>
|
||||
<div class="tc-split-pill-bottom">
|
||||
<$text text={{{ [<jsonOperator>jsonget[operands],<indexOperand>] }}} />
|
||||
</div>
|
||||
</div>
|
||||
</$list>
|
||||
</div>
|
||||
<div class="tc-box-content">
|
||||
Evaluation time <span class="tc-pill"><$text text={{{ [<jsonOperator>jsonget[evaluationTime]fixed[8]] }}}/></span> milliseconds
|
||||
</div>
|
||||
</div>
|
||||
\end inspect-operator
|
||||
|
||||
\procedure inspect-operation(jsonOperation,indexOperation)
|
||||
<div class="tc-box tc-inspect-operation-box">
|
||||
<div class="tc-box-header">
|
||||
<span class="">Evaluation</span>
|
||||
<span class="tc-pill"><$text text=<<indexOperation>> /></span>
|
||||
Evaluation time <span class="tc-pill"><$text text={{{ [<jsonOperation>jsonget[evaluationTime]fixed[8]] }}}/></span> milliseconds
|
||||
</div>
|
||||
<div class="tc-box-content">
|
||||
<$list filter="[<jsonOperation>jsonindexes[operators]nsort[]]" variable="indexOperator">
|
||||
<$let
|
||||
transclusion={{{ [[operator-]addsuffix<indexOperator>] }}}
|
||||
jsonOperator={{{ [<jsonOperation>jsonextract[operators],<indexOperator>] }}}
|
||||
>
|
||||
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonOperator>jsonextract[input]] }}} class="tc-box tc-inspect-input-box"/>
|
||||
<$transclude $variable="inspect-operator" jsonOperator=<<jsonOperator>>/>
|
||||
</$let>
|
||||
</$list>
|
||||
<$list filter="[<jsonOperation>jsonindexes[operators]nsort[]last[1]]" variable="indexOperator">
|
||||
<$let
|
||||
transclusion={{{ [[operator-]addsuffix<indexOperator>] }}}
|
||||
jsonOperator={{{ [<jsonOperation>jsonextract[operators],<indexOperator>] }}}
|
||||
>
|
||||
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonOperator>jsonextract[output]] }}} class="tc-box tc-inspect-output-box"/>
|
||||
</$let>
|
||||
</$list>
|
||||
</div>
|
||||
</div>
|
||||
\end inspect-operation
|
||||
|
||||
\procedure inspect-run(jsonRun)
|
||||
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonRun>jsonextract[input]] }}} class="tc-box tc-inspect-input-box"/>
|
||||
<div class="tc-box tc-inspect-run-box">
|
||||
<div class="tc-box-header">
|
||||
<span class="">
|
||||
<%if [<jsonRun>jsonget[prefix]!match[]] %>
|
||||
<$text text={{{ [<jsonRun>jsonget[prefix]] }}} />
|
||||
<$text text=" shortcut for "/>
|
||||
<$text text={{{ [<jsonRun>jsonget[prefixName]addprefix[:]] }}} />
|
||||
<%else%>
|
||||
<$text text={{{ [<jsonRun>jsonget[prefixName]addprefix[:]] }}} />
|
||||
<%endif%>
|
||||
</span>
|
||||
<%if [<jsonRun>jsonindexes[suffixes]length[]compare:number:gt[0]] %>
|
||||
<$list filter="[<jsonRun>jsonindexes[suffixes]nsort[]]" variable="indexSuffix">
|
||||
<span class="tc-pill">
|
||||
:<$text text={{{ [<jsonRun>jsonget[suffixes],<indexSuffix>] }}} />
|
||||
</span>
|
||||
</$list>
|
||||
<%endif%>
|
||||
Evaluation time <span class="tc-pill"><$text text={{{ [<jsonRun>jsonget[evaluationTime]fixed[8]] }}}/></span> milliseconds
|
||||
</div>
|
||||
<div class="tc-box-content">
|
||||
<div class="tc-inspect-operations-wrapper">
|
||||
<$list filter="[<jsonRun>jsonindexes[operations]nsort[]]" variable="indexOperation">
|
||||
<$let transclusion={{{ [[operation-]addsuffix<indexOperation>] }}}>
|
||||
<$transclude $variable="inspect-operation" jsonOperation={{{ [<jsonRun>jsonextract[operations],<indexOperation>] }}} indexOperation=<<indexOperation>>/>
|
||||
</$let>
|
||||
</$list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
\end inspect-run
|
||||
|
||||
\procedure inspect-filter-output-unframed(jsonOutput,orientation:"horizontal")
|
||||
<$scrollable bind={{{ [<qualify "$:/temp/filter-inspector/">addsuffix<filter>] }}}>
|
||||
<div class={{{ tc-inspect-filter-box tc-inspect-filter-box-unframed [<orientation>match[horizontal]then[tc-inspect-filter-box-horizontal]] +[join[ ]] }}}>
|
||||
<$list filter="[<jsonOutput>jsonindexes[runs]nsort[]]" variable="indexRun">
|
||||
<$let transclusion={{{ [[run-]addsuffix<indexRun>] }}}>
|
||||
<$transclude $variable="inspect-run" jsonRun={{{ [<jsonOutput>jsonextract[runs],<indexRun>] }}}/>
|
||||
</$let>
|
||||
</$list>
|
||||
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonOutput>jsonextract[output]] }}} class="tc-box tc-inspect-output-box"/>
|
||||
</div>
|
||||
</$scrollable>
|
||||
\end inspect-filter-output-unframed
|
||||
|
||||
\procedure inspect-filter-output(jsonOutput,orientation:"horizontal")
|
||||
<$scrollable bind={{{ [<qualify "$:/temp/filter-inspector/">addsuffix<filter>] }}}>
|
||||
<div class={{{ tc-inspect-filter-box [<orientation>match[horizontal]then[tc-inspect-filter-box-horizontal]] +[join[ ]] }}}>
|
||||
<div class="tc-box">
|
||||
<div class="tc-box-header">
|
||||
Filter
|
||||
<span class="tc-pill"><$text text={{{ [<jsonOutput>jsonget[inputFilter]] }}}/></span>
|
||||
Evaluation time <span class="tc-pill"><$text text={{{ [<jsonOutput>jsonget[evaluationTime]fixed[8]] }}}/></span> milliseconds
|
||||
</div>
|
||||
<div class="tc-box-content">
|
||||
<$list filter="[<jsonOutput>jsonindexes[runs]nsort[]]" variable="indexRun">
|
||||
<$let transclusion={{{ [[run-]addsuffix<indexRun>] }}}>
|
||||
<$transclude $variable="inspect-run" jsonRun={{{ [<jsonOutput>jsonextract[runs],<indexRun>] }}}/>
|
||||
</$let>
|
||||
</$list>
|
||||
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonOutput>jsonextract[output]] }}} class="tc-box tc-inspect-output-box"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</$scrollable>
|
||||
\end inspect-filter-output
|
||||
|
||||
\procedure inspect-filter(filter,inputFilter:"[all[tiddlers]]",orientation:"horizontal")
|
||||
<$transclude $variable="inspect-filter-output" jsonOutput={{{ [subfilter<inputFilter>inspect<filter>] }}} orientation=<<orientation>> />
|
||||
\end inspect-filter
|
||||
@@ -0,0 +1,29 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/modules/inspect.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for inspecting the evaluation of a filter
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var getWrappers = $tw.plugins.internals.getWrappers;
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.inspect = function(source,operator,options) {
|
||||
var inputFilter = operator.operands[0] || "",
|
||||
results,
|
||||
wrappers = getWrappers(function(output) {
|
||||
results = output;
|
||||
},inputFilter);
|
||||
// Compile the filter with wrapper functions to log the details
|
||||
var compiledFilter = options.wiki.compileFilter(inputFilter,{
|
||||
wrappers: wrappers
|
||||
});
|
||||
compiledFilter.call(options.wiki,source,options.widget);
|
||||
return [JSON.stringify(results)];
|
||||
};
|
||||
212
plugins/tiddlywiki/internals/filterinspection/modules/startup.js
Normal file
212
plugins/tiddlywiki/internals/filterinspection/modules/startup.js
Normal file
@@ -0,0 +1,212 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/modules/startup.js
|
||||
type: application/javascript
|
||||
module-type: startup
|
||||
|
||||
Install hooks
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// Export name and synchronous status
|
||||
exports.name = "internals-plugin";
|
||||
exports.before = ["startup"];
|
||||
exports.synchronous = true;
|
||||
|
||||
exports.startup = function() {
|
||||
// Publish public methods
|
||||
$tw.plugins = $tw.plugins || {};
|
||||
$tw.plugins.internals = {
|
||||
getWrappers: getWrappers
|
||||
};
|
||||
// We accumulate the output of the filter inspection into an array. We can't directly write to the wiki since we might be in
|
||||
// the middle of the refresh cycle, when writes to the wiki are not allowed
|
||||
var accumulator = [];
|
||||
// Add our hook for each filter evaluation
|
||||
$tw.hooks.addHook("th-filter-evaluation",function(filterString,wrappers) {
|
||||
// Check that filter observation is enabled
|
||||
if($tw.wiki.getTiddlerText("$:/config/FilterObservationionEnabled","no") !== "yes") {
|
||||
return wrappers;
|
||||
}
|
||||
// Get the list of filters to be inspected
|
||||
var inspectedFilters = $tw.wiki.getTiddlersWithTag("$:/tags/InspectableFilter");
|
||||
// Check whether this is a filter we want to inspect
|
||||
if(inspectedFilters.indexOf(filterString) === -1) {
|
||||
return wrappers;
|
||||
}
|
||||
// Don't do anything if there are already wrappers
|
||||
if(wrappers.prefix || wrappers.operation || wrappers.operator) {
|
||||
return wrappers;
|
||||
}
|
||||
// Flush the accumulator, making each filter inspection output record into a separate tiddler
|
||||
var flushAccumulator = function() {
|
||||
if(accumulator.length) {
|
||||
$tw.utils.each(accumulator,function(jsonInspectionOutput) {
|
||||
// Get the output as a string
|
||||
var stringInspectionOutput = JSON.stringify(jsonInspectionOutput);
|
||||
// Compute the log prefix and its length
|
||||
var logPrefix = `$:/temp/filter-inspection/${ + $tw.utils.stringifyDate(new Date())}: `,
|
||||
logPrefixLength = logPrefix.length;
|
||||
// Check if the the output is the same as the last log with the same filter
|
||||
var logTitles = [];
|
||||
$tw.wiki.each(function(tiddler,title) {
|
||||
if(title.substring(logPrefixLength) === jsonInspectionOutput.inputFilter) {
|
||||
logTitles.push(title);
|
||||
}
|
||||
});
|
||||
var alreadyLogged = false;
|
||||
$tw.utils.each(logTitles,function(title) {
|
||||
var jsonLog = $tw.wiki.getTiddlerData(title);
|
||||
if($tw.utils.isArrayEqual(jsonLog.output,jsonInspectionOutput.output)) {
|
||||
alreadyLogged = true;
|
||||
}
|
||||
});
|
||||
if(alreadyLogged) {
|
||||
return;
|
||||
}
|
||||
// Add the log tiddler
|
||||
var tiddlerFields = {
|
||||
title: `${logPrefix}${jsonInspectionOutput.inputFilter}`,
|
||||
tags: ["$:/tags/FilterInspectionOutput"],
|
||||
text: stringInspectionOutput,
|
||||
filter: jsonInspectionOutput.inputFilter,
|
||||
type: "application/json"
|
||||
}
|
||||
// console.log("Adding " + JSON.stringify(tiddlerFields));
|
||||
$tw.wiki.addTiddler(new $tw.Tiddler($tw.wiki.getCreationFields(),$tw.wiki.getModificationFields(),tiddlerFields));
|
||||
});
|
||||
accumulator = [];
|
||||
}
|
||||
};
|
||||
// Get our wrappers
|
||||
return getWrappers(function(output) {
|
||||
// Schedule a flush
|
||||
if(accumulator.length === 0) {
|
||||
$tw.utils.nextTick(function() {
|
||||
flushAccumulator();
|
||||
});
|
||||
}
|
||||
accumulator.push(output);
|
||||
},filterString);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Return the wrappers for evaluating a given filter
|
||||
fnDone is a function that will be called with the output of the filter evaluation as the single argument
|
||||
inputFilter is the filter to be evaluated
|
||||
*/
|
||||
function getWrappers(fnDone,inputFilter) {
|
||||
// Skeleton output record
|
||||
var output = {
|
||||
inputFilter: inputFilter,
|
||||
input: [],
|
||||
runs: []
|
||||
};
|
||||
// Keep track of where the current run and the current operation are being written
|
||||
var currentRun,currentOperation;
|
||||
// The starting evaluation time stamp
|
||||
var filterStartTime;
|
||||
// Compile the filter with wrapper functions to log the details
|
||||
return {
|
||||
start: function(source) {
|
||||
// Save the input so that we have it in the output record
|
||||
source(function(tiddler,title) {
|
||||
output.input.push(title);
|
||||
});
|
||||
// Start the timer
|
||||
filterStartTime = $tw.utils.timer();
|
||||
},
|
||||
prefix: function(filterRunPrefixFunction,operationFunction,innerOptions) {
|
||||
// Function to be called at the start of each filter run
|
||||
return function(results,innerSource,innerWidget) {
|
||||
// Save the details of this filte run
|
||||
var details ={
|
||||
input: results.toArray(),
|
||||
prefixName: innerOptions.prefixName,
|
||||
prefix: innerOptions.prefix,
|
||||
suffixes: innerOptions.suffixes,
|
||||
operations: []
|
||||
};
|
||||
// Save the current run so that we can add operations to it
|
||||
currentRun = details.operations;
|
||||
// Save the start time
|
||||
var startTime = $tw.utils.timer();
|
||||
// Get the filter run prefix function
|
||||
var innerResults = filterRunPrefixFunction.call(null,operationFunction,innerOptions);
|
||||
// Invoke the filter run
|
||||
innerResults(results,innerSource,innerWidget);
|
||||
// Save the end time
|
||||
details.evaluationTime = $tw.utils.timer(startTime);
|
||||
// Save the results of the filter run
|
||||
details.output = results.toArray();
|
||||
output.runs.push(details);
|
||||
};
|
||||
},
|
||||
operation: function(operationFunction,operation) {
|
||||
// Record the operation
|
||||
var details = {
|
||||
operators: []
|
||||
}
|
||||
// Save the start time
|
||||
var startTime = $tw.utils.timer();
|
||||
// Keep track of where the current operation should be being written
|
||||
currentOperation = details.operators;
|
||||
// Invoke the operation
|
||||
operationFunction();
|
||||
// Save the end time
|
||||
details.evaluationTime = $tw.utils.timer(startTime);
|
||||
// Save the results of the operation
|
||||
currentRun.push(details);
|
||||
},
|
||||
operator: function(operatorFunction,innerSource,innerOperator,innerOptions) {
|
||||
// Record the operator
|
||||
var details = {
|
||||
operatorName: innerOperator.operatorName,
|
||||
operands: innerOperator.operands,
|
||||
parseTree: innerOperator.parseTree,
|
||||
prefix: innerOperator.prefix,
|
||||
suffix: innerOperator.suffix,
|
||||
suffixes: innerOperator.suffixes,
|
||||
regexp: innerOperator.regexp,
|
||||
input: []
|
||||
};
|
||||
// Copy the input
|
||||
innerSource(function(tiddler,title) {
|
||||
details.input.push(title);
|
||||
});
|
||||
// Save this operation
|
||||
currentOperation.push(details);
|
||||
// Save the start time
|
||||
var startTime = $tw.utils.timer();
|
||||
// Invoke the operator
|
||||
var innerResults = operatorFunction.apply(null,Array.prototype.slice.call(arguments,1));
|
||||
// Save the end time
|
||||
details.evaluationTime = $tw.utils.timer(startTime);
|
||||
// Make sure the results are an array so that we can store them
|
||||
if(!$tw.utils.isArray(innerResults)) {
|
||||
var resultArray = [];
|
||||
innerResults(function(tiddler,title) {
|
||||
resultArray.push(title);
|
||||
});
|
||||
innerResults = resultArray;
|
||||
}
|
||||
// Store the results in the output
|
||||
details.output = innerResults;
|
||||
// Return the results
|
||||
return innerResults;
|
||||
},
|
||||
done: function(results) {
|
||||
// Store evaluation time
|
||||
output.evaluationTime = $tw.utils.timer(filterStartTime);
|
||||
// Save the results of the filter evaluation
|
||||
output.output = results;
|
||||
// console.log(`Inspected ${JSON.stringify(output,null,4)}`);
|
||||
// Invoke the done function
|
||||
if(fnDone) {
|
||||
fnDone(output);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
188
plugins/tiddlywiki/internals/filterinspection/styles.tid
Normal file
188
plugins/tiddlywiki/internals/filterinspection/styles.tid
Normal file
@@ -0,0 +1,188 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/styles
|
||||
tags: $:/tags/Stylesheet
|
||||
|
||||
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline macrocallblock
|
||||
|
||||
/*
|
||||
** Headed box and pills
|
||||
*/
|
||||
|
||||
.tc-box {
|
||||
border: 1px solid var(--box-foreground-color););
|
||||
border-radius: 4px;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
.tc-box .tc-box {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.tc-box-header {
|
||||
padding: 0.25em;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
color: var(--box-background-color);
|
||||
fill: var(--box-background-color);
|
||||
background-color: var(--box-foreground-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tc-box-header svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin-left: 0.25em;
|
||||
}
|
||||
|
||||
.tc-box-header button {
|
||||
color: var(--box-background-color);
|
||||
background-color: var(--box-foreground-color);
|
||||
}
|
||||
|
||||
.tc-box-content {
|
||||
min-width: 4em;
|
||||
padding: 0.25em;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
color: var(--box-foreground-color);
|
||||
fill: var(--box-foreground-color);
|
||||
background-color: var(--box-background-color);
|
||||
}
|
||||
|
||||
.tc-box-content-list-scollable {
|
||||
margin: -0.25em;
|
||||
max-height: 25vh;
|
||||
width: 12em;
|
||||
}
|
||||
|
||||
.tc-box-content-list {
|
||||
}
|
||||
|
||||
.tc-box-content-list-item {
|
||||
font-size: 0.7em;
|
||||
line-height: 1.1;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
.tc-box-content-list-more {
|
||||
font-size: 0.7em;
|
||||
line-height: 1.1;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
.tc-box-content-full-width-button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tc-box-content-list-more,
|
||||
.tc-box-content-list-more .tc-btn-invisible {
|
||||
color: var(--box-background-color);
|
||||
fill: var(--box-background-color);
|
||||
background-color: var(--box-foreground-color);
|
||||
}
|
||||
|
||||
.tc-box-content-list-item:nth-child(even) {
|
||||
background: rgb(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.tc-box-content-list-empty {
|
||||
|
||||
}
|
||||
|
||||
.tc-pill {
|
||||
padding: 0.125em 0.25em;
|
||||
margin: 0 0.25em;
|
||||
border-radius: 6px;
|
||||
color: var(--box-foreground-color);
|
||||
background-color: var(--box-background-color);
|
||||
}
|
||||
|
||||
.tc-split-pill {
|
||||
display: inline-block;
|
||||
padding: 0.125em 0.25em;
|
||||
margin: 0 0.25em;
|
||||
border-radius: 6px;
|
||||
color: var(--box-foreground-color);
|
||||
background-color: var(--box-background-color);
|
||||
}
|
||||
|
||||
.tc-split-pill-top {
|
||||
border-bottom: 1px solid var(--box-foreground-color);
|
||||
}
|
||||
|
||||
.tc-split-pill-bottom {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** Filter Inspection
|
||||
*/
|
||||
|
||||
.tc-inspect-filter-box {
|
||||
--box-background-color: <<colour code-border>>;
|
||||
--box-foreground-color: <<colour code-foreground>>;
|
||||
}
|
||||
|
||||
.tc-inspectable-filter-box {
|
||||
--box-background-color: #ffebe1;
|
||||
--box-foreground-color: #ff3f00;
|
||||
}
|
||||
|
||||
.tc-inspectable-filter-trace-box {
|
||||
--box-background-color: #ffdec1;
|
||||
--box-foreground-color: #ff7a00;
|
||||
}
|
||||
|
||||
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal > .tc-box > .tc-box-content,
|
||||
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal.tc-inspect-filter-box-unframed,
|
||||
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal .tc-inspect-run-box > .tc-box-content,
|
||||
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal .tc-inspect-operation-box > .tc-box-content,
|
||||
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal .tc-inspect-operator-box > .tc-box-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.tc-inspectable-filter-box > .tc-box-content > ol {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.tc-inspect-operations-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.tc-inspect-run-box {
|
||||
--box-background-color: #ffffcc;
|
||||
--box-foreground-color: #444400;
|
||||
}
|
||||
|
||||
.tc-inspect-operation-box {
|
||||
--box-background-color: #ccffcc;
|
||||
--box-foreground-color: #004400;
|
||||
}
|
||||
|
||||
.tc-inspect-operator-box {
|
||||
--box-background-color: #ffcccc;
|
||||
--box-foreground-color: #440000;
|
||||
}
|
||||
|
||||
.tc-box.tc-inspect-input-box {
|
||||
--box-background-color: #ffccff;
|
||||
--box-foreground-color: #440044;
|
||||
}
|
||||
|
||||
.tc-box.tc-inspect-output-box {
|
||||
--box-background-color: #4fd3d3;
|
||||
--box-foreground-color: #004444;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/tests/wikitext/Simple
|
||||
description: Test filter inspection
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure test-filter()
|
||||
1 2 3 :sort[length[]add[1]]
|
||||
\end
|
||||
|
||||
\function test-filter-wrapper()
|
||||
[inspect<test-filter>]
|
||||
\end
|
||||
|
||||
<$text text=<<test-filter>>/>
|
||||
-
|
||||
<$text text={{{ [<test-filter-wrapper>jsonindexes[]join[,]] }}}/>
|
||||
-
|
||||
<$text text={{{ [<test-filter-wrapper>jsonindexes[inputFilter]join[,]] }}}/>
|
||||
-
|
||||
<$text text={{{ [<test-filter-wrapper>jsonindexes[runs]join[,]] }}}/>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>1 2 3 :sort[length[]add[1]]-evaluationTime,input,inputFilter,output,runs--0,1,2,3</p>
|
||||
@@ -0,0 +1,3 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/viewtemplatebody
|
||||
|
||||
<$transclude $variable="inspect-filter-output" jsonOutput={{!!text}} />
|
||||
@@ -0,0 +1,5 @@
|
||||
title: $:/plugins/tiddlywiki/internals/filterinspection/cascades/viewtemplatebody
|
||||
tags: $:/tags/ViewTemplateBodyFilter
|
||||
list-before:
|
||||
|
||||
[tag[$:/tags/FilterInspectionOutput]type[application/json]then[$:/plugins/tiddlywiki/internals/filterinspection/viewtemplatebody]]
|
||||
@@ -0,0 +1,2 @@
|
||||
title: $:/state/tab--1498284803
|
||||
text: $:/core/ui/AdvancedSearch/Filter
|
||||
@@ -0,0 +1,2 @@
|
||||
title: $:/state/tab--251342953
|
||||
text: $:/plugins/tiddlywiki/internals/filterinspection/InspectResultsTab
|
||||
@@ -0,0 +1,2 @@
|
||||
title: $:/config/FilterObservationionEnabled
|
||||
text: yes
|
||||
@@ -0,0 +1,5 @@
|
||||
title: $:/plugins/tiddlywiki/internals/testfilter
|
||||
tags: $:/tags/InspectableFilter
|
||||
type: text/plain
|
||||
|
||||
[list[$:/StoryList]]
|
||||
@@ -2,6 +2,6 @@
|
||||
"title": "$:/plugins/tiddlywiki/internals",
|
||||
"name": "Internals",
|
||||
"description": "Tools for exploring the internals of TiddlyWiki",
|
||||
"list": "readme",
|
||||
"list": "readme docs",
|
||||
"stability": "STABILITY_2_STABLE"
|
||||
}
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
title: $:/plugins/tiddlywiki/internals/readme
|
||||
|
||||
This plugin adds features to help explore the internals of TiddlyWiki:
|
||||
This plugin adds several features to help explore the internals of TiddlyWiki, and to debug wikitext and filters.
|
||||
|
||||
* New preview panes showing:
|
||||
** the parse tree
|
||||
** the widget tree
|
||||
** the raw HTML output
|
||||
!! Inspecting Filter Traces
|
||||
|
||||
The first two include a dropdown for choosing block vs. inline parsing mode.
|
||||
Filter inspection is based on a schematic visualisation that traces all the steps involved in evaluating a filter. These traces can be generated and accessed in several ways:
|
||||
|
||||
* Via two new tabs under the Advanced Search filter results:
|
||||
** The ''Inspect'' tab shows the schematic trace for the current filter
|
||||
** The ''Observe'' tab allows the current filter to be logged in the background. A new trace is generated every time the filter is evaluated, regardless of the context, if the results are different from previous evaluations
|
||||
* Directly using the `<<inspect-filter>>` procedure, or the underlying `inspect[]` operator
|
||||
|
||||
Note that observing a filter is not the same as logging it. Observing a filter means that the filter is evaluated in the background, and a new trace is generated every time the filter is evaluated, regardless of the context. Logging a filter means that the filter is evaluated in the background, but only if the results are different from previous evaluations.
|
||||
|
||||
Filter observation has a performance impact, and disables certain optimisations such as caching of compiled filters.
|
||||
|
||||
!! Inspecting Parse Trees and Widget Trees
|
||||
|
||||
New preview panes for the tiddler editor that show
|
||||
|
||||
* the parse tree
|
||||
* the widget tree
|
||||
* the raw HTML output
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
title: $:/plugins/tiddlywiki/internals/styles
|
||||
tags: $:/tags/Stylesheet
|
||||
|
||||
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline macrocallblock
|
||||
Reference in New Issue
Block a user