\define em-checkTrigger()
<$vars
template={{!!title}}
trigger={{!!em-trigger}}
trigger-end={{!!em-triggerend}}
triggexp={{{ [{!!em-trigger}escaperegexp[]] }}}
triggendexp={{{ [enlist{!!em-triggerend}escaperegexp[]join[|]addprefix[(]addsuffix[)+]split[\/]join[/]trim[]] }}}
before={{{ [<text>splitbefore{!!em-trigger}] }}}
before-length={{{ [<text>splitbefore{!!em-trigger}length[]] }}}
trigger-length={{{[{!!em-trigger}length[]]}}}
>
...\whitespace trim
\define em-showPopup()<$action-popupcaret $state=<<em-state>>/><$action-setfield $tiddler=<<em-state>> template=<<matchedTemplate>> fragment=<<matchedFragment>>/><$action-setfield $tiddler="test" state=<<em-state>> />\end
\define em-updatePopupState()<$list filter="[<matched>match[false]]"><$action-deletetiddler $tiddler=<<em-state>>/></$list><$list filter="[<matched>match[true]]"><<em-showPopup>></$list>\end
\define em-checkNextTrigger() <$list filter="""[all[tiddlers]tag[$:/tags/EditorMagic]!has[draft.of]after<template>]""" emptyMessage=<<em-updatePopupState>>> <<em-checkTrigger>> </$list>\end
\define em-checkTrigger() <$vars template={{!!title}} trigger={{!!em-trigger}} trigger-end={{!!em-triggerend}} triggexp={{{ [{!!em-trigger}escaperegexp[]] }}} triggendexp={{{ [enlist{!!em-triggerend}escaperegexp[]join[|]addprefix[(]addsuffix[)+]split[\/]join[/]trim[]] }}} before={{{ [<text>splitbefore{!!em-trigger}] }}} before-length={{{ [<text>splitbefore{!!em-trigger}length[]] }}} trigger-length={{{[{!!em-trigger}length[]]}}} em-itemfilter = {{!!em-itemfilter}}><$action-log $message=<<template>>/><$list filter="""[<text>search<trigger>] +[splitregexp<triggexp>] +[!prefix[ ]!search::regexp<triggendexp>] +[last[]]""" emptyMessage=<<em-checkNextTrigger>> variable="em-fragment"> <$vars before-length={{{[<text>splitregexp<triggexp>butlast[]join<trigger>length[]]}}}> <$action-log $message={{{[[detected: ]addsuffix<template>]}}}/> <$list filter="[<template>!has[em-itemfilter]] ~[subfilter<em-itemfilter>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>> <$list filter="[<em-fragment>length[]add<before-length>add<trigger-length>match<selectionEnd>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>> <$list filter="[<em-fragment>length[]compare:number:lt<fragmentLength>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>> <$vars matched="true" fragmentLength={{{[<em-fragment>length[]]}}} matchedFragment=<<em-fragment>> matchedTemplate=<<template>> > <<em-checkNextTrigger>> </$vars> </$list> </$list> </$list> </$vars></$list></$vars>\end
\define em-checkAllTriggers()<$vars text={{{ [{!!text}split[]first<selectionEnd>join[]] }}} ><$list filter="""[all[tiddlers]tag[$:/tags/EditorMagic]!has[draft.of]first[]]"""> <$vars matched="false" fragmentLength="9999999"> <<em-checkTrigger>> </$vars></$list></$vars>\end
\define em-inputActions()<$action-withselection actions=<<em-checkAllTriggers>> />\end
<$set name=em-state value=<<qualify $:/state/EditorMagicPopupState>>><$edit
field="text" class="tc-edit-texteditor tc-edit-texteditor-body" placeholder={{$:/language/EditTemplate/Body/Placeholder}} tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[text]then[true]] ~[[false]] }}} cancelPopups="yes" inputActions=<<em-inputActions>>
><$set
name="targetTiddler" value=<<currentTiddler>>
><$list
filter="[all[shadows+tiddlers]tag[$:/tags/EditorToolbar]!has[draft.of]]"
><$reveal
type="nomatch" state=<<config-visibility-title>> text="hide" class="tc-text-editor-toolbar-item-wrapper"
><$transclude
tiddler="$:/core/ui/EditTemplate/body/toolbar/button" mode="inline"
/></$reveal></$list></$set><$reveal type="popup" state=<<em-state>> class="editormagic-popup tc-popup-keep"><div><$set name="selectionEnd" filter="[<em-state>get[selection-end]]" select="0">
{{||EditorMagic/_Popup}}
</$set></div></$reveal></$edit></$set>Just a quick look at http://editormagic2.tiddlyspot.com/ and I notice its case sensitive can it be insensitive on input, sensitive on the result?
I would however be keen to be able to provide my own subtiddler title generator. For example tiddlername - n, tiddlername/something N or behind system $:/namespace/tiddlername(n), even a supplied title. This would allow the transcluded tiddlers be part of other solutions.
Note: If I enter [[ol and highlight the choice it goes white, unlike a few mins ago.
Perhaps you missed it, but I offered to start populating widget snipits for insertion with your instructions on how to.
Love your work, this is seriously exciting.
The itemfilter stuff works. There is a noticeable delay which I estimate to be proportional to the number of items i.e the list of items is much longer for [[ than for << or <$ ... or perhaps more correctly expressed, it's probably proportional to the complexity of the itemfilter.
\define em-checkTrigger() <$vars template={{!!title}} trigger={{!!em-trigger}} trigger-end={{!!em-triggerend}} triggexp={{{ [{!!em-trigger}escaperegexp[]] }}} triggendexp={{{ [enlist{!!em-triggerend}escaperegexp[]join[|]addprefix[(]addsuffix[)+]split[\/]join[/]trim[]] }}} before={{{ [<text>splitbefore{!!em-trigger}] }}} before-length={{{ [<text>splitbefore{!!em-trigger}length[]] }}} trigger-length={{{[{!!em-trigger}length[]]}}} em-itemfilter = {{!!em-itemfilter}}><$action-log $message=<<template>>/><$list filter="""[<text>search<trigger>] +[splitregexp<triggexp>] +[!prefix[ ]!search::regexp<triggendexp>] +[last[]]""" emptyMessage=<<em-checkNextTrigger>> variable="em-fragment"> <$vars before-length={{{[<text>splitregexp<triggexp>butlast[]join<trigger>length[]]}}}> <$action-log $message={{{[[detected: ]addsuffix<template>]}}}/> <$list filter="[<em-fragment>length[]add<before-length>add<trigger-length>match<selectionEnd>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>> <$list filter="[<em-fragment>length[]compare:number:lt<fragmentLength>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>> <$list filter="[<template>!has[em-itemfilter]] ~[subfilter<em-itemfilter>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>> <$vars matched="true" fragmentLength={{{[<em-fragment>length[]]}}} matchedFragment=<<em-fragment>> matchedTemplate=<<template>> > <<em-checkNextTrigger>> </$vars> </$list> </$list> </$list> </$vars></$list></$vars>\end
- is the delay coming from the detection code or the display code? For example for [[ just set the popup code to not run any filters and display a static message like "TitlePicker" and see if the delay is still there. If its significantly reduced then we know the delay is mostly from display code, and vice versa
- For the detection code, see if swapping the list with the item-filter to be the innermost one helps with performance. Simple cut and paste.
- I am also unsure if we need this list anymore (after introducing em-itemfilter):
<$list filter="[<em-fragment>length[]add<before-length>add<trigger-length>match<selectionEnd>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>>
I recommend doing a side by side comparison with and without this in some complex text with a lot of unclosed triggers, and see if the behaviour is identical. If it helps avoid even a few false matches it is worth keeping as the filter it runs is a fast one.
I had a quick look at _Popup and TitlePicker. I think they look OK. One potential issue with the vars we set up in _Popup is going to be that they will force the entire popup to redraw itself from scratch on every keystroke, rather than say a title list that just updates itself. Let's see if the display code is causing any performance issues before deciding whether that is worth adressing
In short: don't be in a hurry to have something "final" and publish it [...]
First, again, I really appreciate your help. Even if you say we should just treat it as prototype, I think it is desirable that it at least works fairly OK - and it feels like it is close to doing that :-)
Tests definitely imply it's the detection code. No visible difference when popup runs or doesn't run filters.
- I am also unsure if we need this list anymore (after introducing em-itemfilter):
<$list filter="[<em-fragment>length[]add<before-length>add<trigger-length>match<selectionEnd>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>>
I recommend doing a side by side comparison with and without this in some complex text with a lot of unclosed triggers, and see if the behaviour is identical. If it helps avoid even a few false matches it is worth keeping as the filter it runs is a fast one.No discernible difference in a side by side.
I had a quick look at _Popup and TitlePicker. I think they look OK. One potential issue with the vars we set up in _Popup is going to be that they will force the entire popup to redraw itself from scratch on every keystroke, rather than say a title list that just updates itself. Let's see if the display code is causing any performance issues before deciding whether that is worth adressingPlease elaborate.
Tests definitely imply it's the detection code. No visible difference when popup runs or doesn't run filters.
...
How about a filter that that just detects whether the fragment for titlepicker has disallowed characters?
- I am also unsure if we need this list anymore (after introducing em-itemfilter):
<$list filter="[<em-fragment>length[]add<before-length>add<trigger-length>match<selectionEnd>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>>
- ...
No discernible difference in a side by side.
If you are sure about this, we can remove this list and the variables that are there just for its sake.
[...] forces the entire popup to redraw itself from scratch on every keystroke, rather than say a title list that just updates itself.
<$vars foo={{{ [{!!foo}] }}}>content</$vars>If the value of "foo" in the vars widget changes, the entire widget is destroyed and re-created, which means so is everything inside it.If however you do something like the following, the list updates itself instead of re-drawing from scratch. This is much faster:<$list filter=[prefix{!!fo}]>content</$list>
Hm, since it is always matched against existing strings (e.g titles) is that not enough? I mean the fragment "Editox" is as disallowed as e.g "Edito]]" , is it not? (But I have to admit this logic of mine it feels like I'm stepping back to how it was when before you stepped in when I couldn't tell where the end of the fragment was...)
- I am also unsure if we need this list anymore (after introducing em-itemfilter):
<$list filter="[<em-fragment>length[]add<before-length>add<trigger-length>match<selectionEnd>]" variable="_NULL" emptyMessage=<<em-checkNextTrigger>>>
...No discernible difference in a side by side.If you are sure about this, we can remove this list and the variables that are there just for its sake.As sure as my primitive test is, yes ;-)
Are you saying filtered transclusion {{{...}}} is evaluated for each stroke but $list is not? That sounds like great but I also don't understand how that is possible since listwidgets do update when their filter changes.... don't they?
It was a suggestion that if you find the peformance slowdown unacceptable, then you could replace the title matching filter in the detection code with one that just rejects fragments with disallowed characters. It would be faster though far less accurate.
There are other options that could be explored via refactoring to try and get around the performance issues, but it would be a fair bit of work that may or may not yield results.
Are you saying filtered transclusion {{{...}}} is evaluated for each stroke but $list is not? [...]No. [...] However, I did say that this is only an issue if its the display code causing the performance issues. So based on what you are reporting, I am unsure why you are focusing on this at the moment.
[...] I would recommend getting the functionality as you want it before switching focus to performance.
Saq Imtiaz wrote:[...] I would recommend getting the functionality as you want it before switching focus to performance.Oh!? Do you mean building/polishing tools instead?
Do feel free to remove the $action-log widgets if you don't find them useful or think they are no longer needed.