Crazy todo concept / replacing current tiddler's text

I’ve taken a few shots at this over the years - a super-lightweight way of making todos quickly inline as I’m making notes. I can think of a few ways to do this, but most of the normal ways involve externally storing each todo somewhere and I’m looking for a no-trace way of doing it. Here’s what I have, which promptly breaks TiddlyWiki.

Intended effect/setup:

  • Be able to add todos inline just like if <<todo “this”>> is a todo
    • The macro would wikify to a button
    • Clicking the button would remove the macrocall and just leave the word DONE

What almost works (copy-paste to tiddlywiki.com):

Macro

\define todo(string)
<$button>$string$
<$action-setfield $field="text" $value=<<new-content "$string$">>/>
</$button>
\end
\define new-content(word)
<$vars search-string='\<\<todo\s"$word$"\>\>' replace-string='DONE'>
<$list filter="[all[current]get[text]splitregexp<search-string>join<replace-string>]"><<currentTiddler>></$list>
</$vars>
\end

Example Tiddler

I should really <<todo "call">> my old friend. 

Actually I should <<todo "visit">> my mother while I'm in town too.

which renders as
image

But when I click on the buttons it crashes… I’m not really surprised as it seems kind of crazy, but I’m hoping somebody has tried something like this that works.

I will note that if I enter another tiddler name in the action-setfield so that it outputs somewhere else, that works as intended. The problem is that I’m trying to have it kind of replace itself.

Any ideas?

1 Like

The problem is that macros are NOT functions. They simply “return” their content for further processing, depending entirely upon the “calling context” to decide what to do.

When you reference a macro directly in wikitext, the macro’s content is inserted in place of the macro call, and then that content is automatically processed (“wikified”) by the TWCore parser to produce the output. This gives the impression that the macro itself is a “function” that produces a “return value”.

However, when used as the value of a widget parameter (i.e., in the $action-setfield in your code), the macro content does not get parsed, and is just passed to the widget “as-is”. Thus, in your code above, you are actually replacing the tiddler text with the code from the <<new-content>> macro… and, since that code invokes a $list widget that replaces itself, it gets into an infinite recursion, which locks up and crashes.

Here’s a different approach that uses the “search-replace” filter operator to do what you want:

\define todo(txt)
<$button> $txt$
   <$vars in="""<<todo "$txt$">>""" out="""$txt$ &#x2713;""">
   <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
   </$vars>
</$button>
\end

Note that there’s no need to split/join the text, or to use a regexp pattern match. search-replace[...],[...] simply finds a literal match of the first parameter, and replaces it with the second parameter. In this case, it finds the macro <<todo "...">> and replaces it with the same text, followed by a UNICODE checkmark symbol (the &#x2713;).

Let me know how it goes…

enjoy,
-e

5 Likes

@stobot
I like your idea here that the todo consists primarily of the verb (in a button) with the specific details in the tiddler.

Not withstanding Eric’s solution I am inspired to see a new way to do this on TW5.2.0 here are some ideas;

  • Programmatically scan the action sentences for verbs eg call visit do phone list edit email mail print …
  • Create a “todo button” for each verb, by Replacing the use of the verb in each sentence with say <<verb "verb">>
  • depending on a mode setting or status this will be an action button or just the verb in plain text.
  • the verb macro has access to the current tiddler title, and actioning of this verb could set a status in a field (for independent tiddlers) or in a data tiddler.
  • The same verb may be used zero or more times in a tiddler and zero or more times in a sentence so we need to find a way to uniquify them. My thought is, on saving a tiddler to copy the sentences containing a verb as a fieldname and present the list of actionable sentences at the bottom of tiddlers but this is still open, even to your edit text method.

Another trick may be using a technology such as the freelinks plugin to detect all verbs (displayed) in all tiddlers tagged “actionable” and instead of a link use the “verb” macro.

@stobot - have a look at Shiraz 2.4 and the quick table! See how it create todo list from plain text!
Using the @EricShulman solution you can use an interactive todo list as plain text in the body of tiddler!

These solutions are based scan the tiddler text and render in a custom way!

@EricShulman works perfectly!! As always, I appreciate the extra information greatly - so thank you for that, it makes sense now.

@TW_Tones I can see where you’re going and it makes sense, though it doesn’t quite fit the workflow that I’m looking for. In particular your point about the uniqueness is key. I have a full-blown task management thing going outside of this. For this particular piece I just need a minimal way, while typing comments inline, to flag that I’ll need to go back later and either complete it, or add to my task list for later. Because of this, one block of notes could have many different todos all scattered throughout it, so that was the thought behind the words inside the macro, so I’d have a way to search-replace each specific one one-at-a-time.

Now I will say that before this I had hijacked the mark wikification using ==todo== throughout the code which was easier to type. Using your thoughts around freelinks etc. combining those thoughts would be really nice. For instance, could I do the same thing somehow as @EricShulman fixed for me, but somehow do ==call== like I used to instead of <<todo “call”>> and still get a button to clear it?

@Mohammad I’ve been meaning to review Shiraz for a while now and just took a look. It’s an impressive and extensive piece of work. In fact it’s so extensive it’s a bit overwhelming, which is probably why I keep putting it on my later list. I can certainly see how building the todo list is keystroke-light, but you’re right, I’d still have to figure out how to add the interactivity to it. The format also doesn’t quite fit my workflow either as I can often have multiple todos within a line while most lines have none. Again though, I’ll take another look as I do like the visual style and the cohesiveness of it.

Completely NON-crazy idea - thank you!

As ever @EricShulman’s wikitext brevity wins the day, (IMO). :slight_smile:

So, having had this idea in my mind for a while, when I saw @stobot’s Q I was intrigued to see Eric’s solution. And since it was only a step or two shy of what I truly wanted – a bullet-like todo at the head of a paragraph that could be toggled todo->done->todo... – I jumped on the giant’s shoulders and dug in (and hacked the hell out of his code):

\define todo-done(txt)
<$button class="tc-btn-invisible tc-tiddlylink" style="color:#3a3;"> ''DONE'' &#x2713;
 <$vars in="""<<todo-done "$txt$">>"""
  out="""<<todo "$txt$">>""">
  <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
 </$vars>
</$button>
\end

\define todo(txt)
<$button class="tc-btn-invisible tc-tiddlylink" style="color:red;"> ''$txt$''
 <$vars in="""<<todo "$txt$">>"""
  out="""<<todo-done "$txt$">>""">
  <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
 </$vars>
</$button>
\end

In use:


<<todo "TODO 1:">> We need to explain consciousness.

<<todo "TODO 2:">> Solve dark matter.

And don't forget <<todo "TODO 3:">> Quantum Gravity.

image

Thanks Eric! :nerd_face: :beers:

1 Like

(Editing as I figured it out)
Took @CodaCoder’s code and added timestamp logging (and slightly reformatted)

\define todo-done(txt, log)
<$button class="tc-btn-invisible tc-tiddlylink" tooltip="$log$" style="color: inherit;";>🗹&nbsp;$txt$
  <$vars in="""<<todo-done "$txt$" "$log$">>""" out="""<<todo "$txt$">>""">
    <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
  </$vars>
</$button>
\end

\define todo(txt)
<$button class="tc-btn-invisible tc-tiddlylink" style="color: red;"> ☐&nbsp;$txt$
  <$vars out_base="""<<todo-done "$txt$" " """ out_time=<<now "YYYY-0MM-0DD hh:mm">> out_end=""" ">>"""  >
    <$vars in="""<<todo "$txt$">>""" out={{{ [<out_base>addsuffix[Completed: ]addsuffix<out_time>addsuffix<out_end>] }}}>
      <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
    </$vars>
  </$vars>
</$button>
\end

And (if gifs work here) this is what it looks like in action.
todos

Thanks again everyone!

1 Like

I had to rename some stuff to avoid clashes with mine…

\define todo-doneX(txt)
<$button class="tc-btn-invisible tc-tiddlylink" tooltip=<<now>> style="color:inherit;";>🗹&nbsp;$txt$
 <$vars in="""<<todo-doneX "$txt$">>""" out="""<<todoX "$txt$">>""">
  <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
 </$vars>
</$button>
\end

\define todoX(txt)
<$button class="tc-btn-invisible tc-tiddlylink" style="color: red;"> ☐&nbsp;$txt$
  <$vars in="""<<todoX "$txt$">>""" out="""<<todo-doneX "$txt$">>""">
    <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
  </$vars>
</$button>
\end


<<todoX "call the boss">>

Instead of passing timestamp around, I get it at the time the todo-done is created. I hope that does the trick you’re after…

Thanks for the help @CodaCoder! Your version is certainly cleaner. So that tooltip gets locked in until when? It seems like it might accidently “update” at some other point (during other future edits in another area of the same tiddler?) I’ll do some testing. Thanks!

I’m not sure about the locking in of the tooltip – if I’m following what’s going on, it’s kind of captured at the time (each time) the todo-done is created. IOW, todo doesn’t create one, only the transition from todo to todo-done makes a NEW timestamp.

It was nice to remove the log param.

Be interesting to have @EricShulman give it a lookover.

I do not understand. If I save and refresh, they all show the same time …NOW.

Ah!

Of course… dangers of working live and forgetting to come back and look.

So the timestamp needs to be off-loaded to a field somewhere via an <$action-setfield/> widget.

Good catch @Birthe !

I knew the date thing could get messy :man_shrugging:

@Birthe my version above stores the date in the macro, give it a spin!

@stobot Your version works, no change after refresh. I really like the date and time idea.

1 Like

To all for your consideration;
I like these solutions because they create perhaps what we may call a list of sub tasks. The thing about such lists in single tiddler is they can be generated from a tiddler template and can be used to build checklists in a complex process that you may do more than once, for example “register a domain, host it and start building a website”.

Existing features to keep in mind when doing this;

  • You can use the excise tool to insert macros rather than links/transclusions
  • You could make your own Editor Toolbar button
  • With the right process you could extract all such todo’s (macro calls) to summarise at the bottom or collate from multiple tiddlers in a single view. I would be keen to build a general solution for this.

Finally @pm, TT and I have on pause a project called “Custom Markup”, with custom markup it is trivial to introduce a format like this

Rather than
<<todo “call”>>
do
Must『t Call fred』this week

And it can replace during parsing the call fred with <<todo "call fred">>

Future directions;

As inspired by this thread however I think it would be great if say on tiddlers tagged todo all verbs were found were extracted as smart todo items automatically.

eg
To get the address details call fred!

would perhaps find the get or the call and generate a todo up to the “!”

To <<todo "get the address details call fred!">>

And you could also display icons such as a phone for the verb call.

1 Like

As we can see all verbs in English have past tense equivalents so on actioning “call” could become called.

“Call fred about a dog!”
Becomes
“Called fred about a dog!”

Then if we assume following the first verb is the subject “fred” we could also freelink to the “fred” tiddler if it existed.

A minor suggestion:

What do you think if all of the todos, listed at the top or bottom of tiddler? while you called todo whenever you liked

Hello. First of all, thank you very much for the code. I would like to report a bug (or unexpected behaviour).

With this code

\define todo-done(txt, log)
<$button class="tc-btn-invisible tc-tiddlylink" tooltip="$log$" style="color: inherit;";>🗹&nbsp;$txt$
  <$vars in="""<<todo-done "$txt$" "$log$">>""" out="""<<todo "$txt$">>""">
    <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
  </$vars>
</$button>
\end

\define todo(txt)
<$button class="tc-btn-invisible tc-tiddlylink" style="color: red;"> ☐&nbsp;$txt$
  <$vars out_base="""<<todo-done "$txt$" " """ out_time=<<now "YYYY-0MM-0DD hh:mm">> out_end=""" ">>"""  >
    <$vars in="""<<todo "$txt$">>""" out={{{ [<out_base>addsuffix[Completed: ]addsuffix<out_time>addsuffix<out_end>] }}}>
      <$action-setfield text={{{ [all[current]get[text]search-replace<in>,<out>] }}}/>
    </$vars>
  </$vars>
</$button>
\end

If I have two todos with exact same parameter

<<todo "call the boss">>
<<todo "call the boss">>

Clicking on the second todo will complete the first one.

@Pak That is expected, it would allow you to place the same todo item in a few places in your text and finishing one finished them all.

But stop and think, what this does!

Just because you can why would you?

<<todo "call the boss">>
<<todo "call the boss">>

actually mean? if you must

<<todo "call the boss">>
<<todo "call the boss again">>

or
<<todo "call the boss twice">>

It is only a problem if

<<todo "call the boss">>

Is used in the same tiddler more than once. It works totally okay, when used in another tiddler. I think that makes it easy to remember what we have used before.