I have a vague memory that we don’t have a low level renaming hook and that th-renaming-tiddler is only invoked in response to a specific widget message.
That would explain it! There is a tm-rename-tiddler. Perhaps its tied to that only. Unfortunate if so.
I may have to dig into Relink to see how this can be done.
Thank you!
Renaming and relinking is implemented ag: https://github.com/TiddlyWiki/TiddlyWiki5/blob/3cf71365a5a7a3ce7b6d590433103596b032c6bf/core/modules/wiki-bulkops.js#L34
So if you overwrite those functions, you can run some tests.
Without overwriting at all, I can set breakpoints. I found that on simply editing a tiddler, changing title, and re-saving renameTiddler is not invoked. Which is a shame, because it would invoke the hook. If I have the button checked for “Update Old Name to New Name in the tags and list fields of other tiddlers”, then it will run relinkTiddler, but that does not invoke the hook either. (If the “New Name” tiddler exists, it will invoke a different hook. But I think @saqimtiaz is probably right that this hook is invoked only in limited circumstances.
A pity.
I’m not particularly interested in overriding core tiddler for this. At some point, I may look at Relink, to see if they have other tricks, but it was much more of a “hey, can I do that?” investigation than a pressing need, so it’s going to be low priority.
But if someone has an alternative to offer, I’m all ears!
I have raised this with @Flibbles
thanks for looking into this @Scott_Sauyet
relink needed to overwrite $:/core/ui/EditTemplate/title to intercept renames in edit. if you follow that lead you will find renames are handled first by the navigator widget, it’s relinkOnRename parameter, in the Page template, then is handled by a subset of messages.
see tm-rename and tm-relink and how they relate to a few other messages.
keep in mind rename is a form of clone + relink
have just packed up my desktop to move from a house sit so only on my phone.
I believe this indicates a need to provide access to this essential action through a tag or hack for designers.
eg action on rename
Absolutely. I wonder how many other of these hooks only look to be more widely useful than they really are.
What’s a “hook”?
Is this something in the TW Basement / Cellar most mortal users can ignore?
Just asking.
TT
First a continuous improvement of tiddlywiki through introduction of hackability is a long held tradition. more often than not this has been based on technical merits not popularity.
many of these changes have one thing in common, they leverage existing mechanisms, require few if any additional bytes and open up many possibilities in a way that multiple plugins can use simultaneously.
Consider how widely used relink is, it would have been better if this was available when it was first written. however even if the hack is not widely used I suspect solutions making use of it may.
I for one have a vision for easy to use support for robust tiddler relationships and frankly not being able to ensure referential integrity when renaming a title, without a core override that clashes with relink is a handicap. the renaming of tiddler titles, the primary key of every tiddler, even all tiddlywiki is a key feature.
“Too-Ra-Loo-Ra Too-Ra-Loo-Rye, Ay / And you’ll hum this tune forever.”
I think of it more likely in the castle with Dr. Frank and Igor. But yes, ignorable for most users.
Hooks in TiddlyWiki – as in many programming environments – allow user code to be called by core code when certain interesting events occur. Had the sample above worked the way I was expecting, when a tiddler was being renamed, my code would be run. That’s because I attached my code to the event tm-renaming-tiddler.
Unfortunately, the code that runs this hook isn’t called when I expect it to be called. So this seems a dead-end for my purposes.
I know the Central Park, NY, Carousel well.
By hook or by crook you well simplified understanding of TW Javascript for us masses.
TT
Ah!
The “hook” isn’t “hooking?”
Quite clearly, it’s come unhooked.
The th-renaming-tiddler hook was added to allow plugins, to “catch” rename actions that have been activated through UI actions with the tm-rename-tiddler message.
The TW store itself does not know a rename. The TW store is immutable, so it can not be changed anymore, once written. That means if a tiddler needs to be renamed, the new tiddler has to be written and the old tiddler has to be deleted.
For this usecase, every action in JS is already too late. The warning has to be given in the UI, before the user clicks the OK or Save-edit button.
We do have 2 existing mechanisms the show such a warning.
The default core relink warning, which is related to the tm-relink-tiddler message
and the Invalid Character in Title warning
IMO that’s the only place where such a warning is actionable for users.
The save button triggers the tm-save-tiddler message.
I was able to make something work. I don’t know how fragile it is; I’m certain it won’t cover all possible renaming scenarios, but it might be enough to handle the common user-initiated edit/rename/save combo. It involves using tm-saving-tiddler in place of tm-renaming-tiddler, checking the title and created fields of the new tiddler against the draft.of/draft.title/created fields of the old one. If both created fields match, the title matches draft.title and title does not match draft.of, then we’re in a rename scenario. (Is that logic both necessary and sufficient?) The implementation looks like this:
/*\
title: $:/_/my/core/modules/startup/rename.js
type: application/javascript
module-type: startup
Add hook for renames to update 'Renamed' text field
\*/
"use strict";
// Export name and synchronous status
exports.name = "rename";
exports.platforms = ["browser"];
exports.after = ["startup"];
exports.synchronous = true;
console.log("AAA: Renaming listener: running in global context");
exports.startup= function() {
console.log("BBB: Renaming listener: running in `startup` context");
$tw.hooks.addHook("th-saving-tiddler", function (newTiddler, oldTiddler) {
console.log("CCC: Renaming listener: running inside saving hook");
if (
newTiddler?.fields?.title === oldTiddler?.fields?.['draft.title']
&& newTiddler?.fields?.created === oldTiddler?.fields?.created
&& newTiddler?.fields?.title !== oldTiddler?.fields?.['draft.of']
) {
console.log("DDD: Rename listener: running an actual rename");
console.log('Renaming', newTiddler, oldTiddler);
}
return newTiddler;
});
};
There’s a fourth level I’m logging here compared to the original snippet. That’s because this is now running on every save, and we have to distinguish the actual renames from other saves.
Note well:
This hook allows plugins to inspect or modify tiddlers before they are saved via the confirm toolbar button; the hook is not invoked for tiddlers that are saved through other means, such as state tiddlers created by the ActionSetFieldWidget. (From the Dev site.)
This shows only a technique. It does not demonstrate any of the rationale for this work. I will probably do so in a post soon. But it does seem to offer a reasonably simple way to hook into the rename events without overriding anything in the core.
The OP was an attempt to demonstrate that it doesn’t capture standard edit / rename / save scenarios. I was expecting it to. The idea was to capture the usual way I believe most users rename their tiddlers.
It feels odd to me that it only works with that particular action. As I show in my most recent post, the tm-saving-tiddler hook does not work only with the tm-save-tiddler message. Is there a good reason for this difference?
A big fan of functional programming, I am very happy with that design!
No. TW did grow organically, which causes inconsistencies. The low level API only contains stuff that was needed to support the core UI. Step by step.
With more and more requests from plugin authors, other options have been implemented. Again mainly for very specific usecases. That’s where our th- hooks come from.
There are other inconsistencies. Eg: action-setwidget, does modify tiddlers directly in the wiki store. So it does not “dispatch” an tm-save-tiddler event. …
The TW tm- event-massaging mechanism works well, for what it is used. But “event-bubbling” introduces it’s own set of problems. eg: It does not scale well with plugins that want to catch the same event. …
So that’s why it is as it is.
Understood. I’ve been on plenty of projects with such issues; sometimes the cruft appears in mere months!
But by “is there a good reason for this difference”, I meant more “is there a good reason I shouldn’t submit a PR to address this difference?” I would love to see the rename hook run whenever a user is renaming a tiddler and not only as the result of an action widget.
I think, new potential PRs is something that should be discussed at a GitHub issue.
I did just debug, low level code using single steps. The core emits a change-event, whenever the store is modified. That’s the lowest level event that plugins can listen to.
It does not contain enough info, that would allow us to reliably detect a single tiddler rename. addTiddler info is “pushed” to a tiddler event queue with minimal info only.
IMO this would be the place to add more info.
There is an updateDescriptor object, that contains full “old” and “new” tiddler info, which is needed by internal indexers. It’s right above the change-event handling. We would need to make sure, that the queued elements do not loose references.
I think that would be worth an experiment.
But
What exactly would be the benefit for the core? → We need to discuss the details at GitHub
Ok, let me think about whether I want to chase that down right now. It sounds like a good idea, but now that I have time (post-election) to spend on other things like TW, I have to figure out the priorities of a number of issues that have arisen.
Thank you for the analysis. I’ll look more closely soon.

