Is there any way to read the titles from `$:/HistoryList` without resorting to arcane regexp in a filter?

I have a need to read all the tiddler names from $:/HistoryList in 5.2.3. Unfortunately it appears there are no filter operators available to work with JSON files, so my current solution is this rather verbose filter using regular expressions:

[
[$:/HistoryList]
get[text]
search-replace:g:regexp[\n|\r],[ ]
search-replace:g:regexp[.+?"title":\s*"(.+?)"],[$1~~]
split[~~]
limit[-1]
is[tiddler]
unique[]
]

While it works it has a few problems:

  • It’ll break if there is a tiddler with ~~ in its name
  • It’ll break if there is a tiddler with a quote character in its name (This I can fix by encoding those escapes and decoding them later, but it has the same vulnerability)
  • It’ll break if there is a tiddler with any other character that is escaped in JSON – to some extent I can handle that but only to some extent

I recall that the next version of TW will give some facilities to improve interfacing with JSON but I am interested in making it work in 5.2.3 or even 5.2.2. I could also just write a custom filter but it’s something that’ll ultimately land in a plugin so I am not sure that’s the direction I want to go just yet.

You might see if JSON Mangler will do what you want.

Here’s the filter I use in https://tiddlytools.com/#TiddlyTools%2FHistory:

[{$:/HistoryList}splitregexp[\n]trim[]trim[,]
removeprefix["title": "]removesuffix["]
!prefix[Draft]
search-replace:g[\"],["]
unique[]
reverse[]]

Notes:

  • get $:/HistoryList contents, split into lines, remove leading/trailing whitespace and trailing comma
  • get only the lines starting with "title": " and ending with " and keep only the actual title text
  • ignore entries for “Draft” tiddlers (history item created when editing a tiddler)
  • replace JSON quotes embedded within titles (\") with plain quotes (")
  • eliminate duplicate items
  • sort in reverse order (most recently viewed first)
3 Likes

I have done something very similar to @EricShulman solution but be aware there is value also not displaying tiddlers (found in history) who no longer have a “title” otherwise you may provide “historical links to tiddlers now deleted”.

I also want to point out this approach is what I refer to as “parsing the content of a tiddler” to extract information separately from the “Parsing to render content that TiddlyWiki” does for us.

  • understanding the splitregexp[\n] which splits on each line is key to opening a lot of powerful solutions.
  • This is one approach I use to do “sophisticated things” in tiddlywiki overlooked by many.

Post Script

  • I also use the following macro when listing the items in the history list
    \define close-if-open-button() <$list filter="[list<tv-story-list>match<currentTiddler>]" variable=nul>{{||$:/core/ui/Buttons/close}}</$list>

Then when listing each tiddler <<close-if-open-button>> <$link/> displays the X icon when open in the story and allows you to close it, from the history list like the Open tab.

  • I actually introduce other “by tiddler” buttons to lists as needed, eg add {{||$:/core/ui/Buttons/edit}} in the above.

You might want to check out this thread or this thread, and more specifically this post by Ittayd.

The history information being JSON formatted, it is sensible to use JavaScript to access it. Hence, Ittayd wrote a filter operator to get the history, which is basically a one-liner and thus quite beautiful and robust at the same time. While I strongly tend to do things in WikiText if possible, I do use his filter operator in my wikis for that reason.

When the JSON filter operators will be available with the next release, I’ll probably change back to a WikiText solution, though.

Have a nice day
Yaisog

That’s much more graceful, thank you! I think I might be tad neurotic when it comes to catching all possible edge cases and don’t have much trust in the format of the input I get.

Only two changes I’d make is:

  • add is[tiddler] somewhere in there to remove non-existing tiddlers
  • replace !prefix[Draft] with !is[draft] to be clearer – I am guessing you used prefix because !is[draft] won’t detect deleted draft tiddlers

I see you don’t bother with unescaping things other than quote character which I suppose is fair. I like your solution very much!

Yup, it already stabbed me in the butt as I was working out my solution hence the inclusion of is[tiddler]

I agree it would be more graceful solution but I specifically want to avoid adding a custom filter so I’ll stick to the solution @EricShulman provided. But thanks nonetheless!

With TW v5.2.4 you can use the following code to get the title list

<$list filter="[{$:/HistoryList}jsonindexes[]]" variable=x >
<$list filter="[{$:/HistoryList}jsonextract<x>]" variable=el >
	<$list filter="[<el>jsonget[title]]">

	</$list>
</$list>
</$list>

See: New JSON-operators

2 Likes

Using is[tiddler] will ignore any shadow tiddlers in the history. Perhaps you can use has[title], which will match existing tiddlers AND shadows, but not a non-existent tiddler.

3 Likes

Well that’s an annoying trap. Thanks for the heads up!

Jeremy just posted an even shorter version.

<$list filter="[{$:/HistoryList}jsonindexes[]] :map[{$:/HistoryList}jsonget<currentTiddler>,[title]]"/>
2 Likes

Dang. I forgot where I parked the TARDIS again.

1 Like

So this allows to create breadcrumbs on the fly!

1 Like

2023-01-24 19:23 GMT+1:
Small update in the filter expression to more reliably remove the currently shown tiddler from the list and order the results.


Finally got around to implement a version of the history list with JSON filters (based on Jeremy’s concise version).

history.json (1.6 KB)

Just drag an drop this into a TW and a history button will appear in the PageControls.

For currently open tiddlers, it shows an eye icon. For my workflow that’s better than leaving open tiddlers out completely, as then I might have to scan two lists (history and open) for what I’m looking for.

If you don’t want shadow tiddlers to show up then just delete [is[shadow]] from tiddler-or-shadow.

Style to taste.

Have a nice day
Yaisog

1 Like

IMO you should use a different icon. The icon is used for the core “Timestamp is ON/OFF” switch which has a very high potential to cause confusion and trouble. eg: If the timestamp is switched off and the setting is forgotten it will cause trouble with the recent list.

So I would strongly recommend to use a different icon for your history functionality.

Here is a good Icon resource TW Icons v1.10 — A large collection of icons for TiddlyWiki

Of course. But my intention was to demo a single-tiddler history button implementation. If this were a plugin, I’d add a custom icon.
In my wikis I use this one: https://fonts.gstatic.com/s/i/materialiconsoutlined/history/v12/24px.svg.

I know and it is OK now, that we have additional links for users, where they get their icons from @TW_Tones thx for the link too

I would not be so picky, if the “timestamp toggle” button would be “side effect” free. …

@Yaisog I just had a look at the solution you shared above, a few review points;

  • Don’t bother with an an icon on each listed items
  • Your solution has the “feature” (happened to my own) where if the draft is open you can open the original tiddler
    • On tiddlywiki.com it resolves to one draft if you edit the “original” with an existing draft in place.
  • I put my history button on the viewToolbar as well
  • I found a Menu bar history dropdown also helpful
  • The full historical list in a sidebar tab helps and allows additional feratures such as direct to edit, copy title, change count.
  • Used padding: 0 0 0 .5em; to improve the look of the title in the dropdown

Thanks for sharing

I cant share my solution just yet, but wanted to share some of the ideas arising.