List of last visited tiddlers

Greetings and hallucinations!

Not sure if this can be done or not. I would like to have a certain tiddler be my default tiddler and have a list of the last few tiddlers that were visited (not edited) in the last few sessions of having it open. When I start my wiki, I’d like to see a history of where I was last session in my default tiddler.

I had been using the default tiddlers set to [list[$:/StoryList]], which works fine, but I’m coming up with an introductory tiddler which I would like to always open by itself when the wiki starts up and no other tiddlers. I would also like this list to be saved when I save the wiki without having to press an extra button to save the list. I could use something like the Views Plugin, but that would be an extra step to create and save. I don’t necessarily want to reopen that last few tiddlers I viewed which the views plugin would do.

Any thoughts? Can it even be done?

One simple way is to create a startup tiddler to make a copy of the StoryList tiddler

This can be done by making a tiddler with the tag $:/tags/StartupAction/Browser with this text content:

<$action-setfield $tiddler="$:/StoryListPrevious" list={{$:/StoryList!!list}}/>

Then in your default tiddler, list those titles:

{{{[list[$:/StoryListPrevious]]}}}

When the wiki renders, the $:/StoryList will be overwritten to contain only your default tiddler. However, prior to that overwrite, the startup action will execute and preserve the contents.

1 Like

Thanks @btheado. It works well. Can I do the same thing $:/HistoryList?

Edit: I took a look at $:/HistoryList and it doesn’t have a list field. I was thinking that it had a list of all tiddlers viewed over several days like the Recent list, but I was wrong. I’d like to be able to have a few days of history show if that’s possible.

Using this instead would allow the list to survive/grow across multiple restarts:

<$action-listops $tiddler="$:/StoryListPrevious" $field="list" $filter="[list[my-$:/StoryListPrevious]]  [list[$:/StoryList]]"/>

However it will grow forever with every unique tiddler you had open at the time of any save then reload. You could control the size like this:

<$action-listops $tiddler="$:/StoryListPrevious" $field="list" $filter="[list[my-$:/StoryListPrevious]]  [list[$:/StoryList]] :and[[last[50]]"/>

Limiting with “several days” is harder because the storylist doesn’t have any information about time/date.

But maybe you are asking for the list of navigated tiddlers and not what the story list happened to contain when you saved and reloaded. Those two are very different.

The $:/HistoryList does track navigation, but its format is json. Also that tiddler might not be saved by default. Both of those obstacles should be surmountable.

The titles in can be extracted the json in $:/HistoryList using jsonindexes and jsonget operators as mentioned here:

https://tiddlywiki.com/#%24%3A%2Fcore%2Fsave%2Fall - from this it looks like $:/HistoryList is excluded from saving. But it also looks like you should be able to add it back by defining the variable publishFilter to have the value $:/HistoryList. Place that variable definition in a tiddler tagged with $:/tags/Global.

The HistoryList tiddler had to be removed from saves, because it grows unlimited. After some time users had a multi-megabyte wiki with just a view 100 tiddlers in them. It’s important to remove it from time to time

2 Likes

Thanks. That’s very helpful.

I was thinking the below action-listops widget could be used in a startup tiddler to auto-trim to a certain number of entries, but I’m seeing extra set of square braces in the resulting json and I haven’t figured out why yet. Here I have it as a button instead of a startup action for easy testing.

<$button>
trim history
<$action-listops
  $tiddler="$:/HistoryList"
  $field="text"
  $filter="[{$:/HistoryList}jsonindexes[]last[3]] :map[{$:/HistoryList}jsonextract<currentTiddler>] :and[join[, ]]"/>
</$button>

Hi @pmario

In the Multi-Column layout I’m using multiple history list tiddlers
They all start with $:/HistoryList
Would it be possible for the core to remove all tiddlers starting with $:/HistoryList?

Edit: (sorry for my OT post)

Thank you,
Simon

It’s already in the TW core!

The $:/core/save/all shadow tiddler contains a definition for saveTiddlerFilter(), which is used to determine which tiddlers are actually retained when saving the file.

This filter already includes “-[prefix[$:/HistoryList]]” which effectively discards all tiddlers that begin with $:/HistoryList.

-e

Oh, I didn’t know that @EricShulman

Thank you very much!
I was worrying about bloating the wikies

Best wishes,
Simon

If you did not change the $:/core/save/all tiddler it should be prefixed already. We did implement that quite some time ago

See: https://tiddlywiki.com/#%24%3A%2Fcore%2Fsave%2Fall

Another approach I have employed is to create a form of logout button, the last thing you do before you leave the wiki after a bit of work. Once you develop this habbit you can place a lot of logic in there to save and maintain anything you want. Of course most times doing this when you start a wiki with wiki start up actions is almost equivalent and with that you dont need to trigger.

  • Thus you allow the history list to be saved and before its cleared save it for later perhaps with a size limit.
  • There are few details you need to address such as the history list will contain tiddlers that have being renamed or deleted.
    • A simple trick is to test that the actual tiddler exists before listing it, and here you could trim those that are older.
  • I actaly find the history list being cleared on reload useful, say once I finish work in one project and start another. If you build a longer term history I suggest keeping the existing mechanisium but collate the longer history in a seperate data tiddler.

It can be done by parsing the historylist like this:

\define title-string() "title": "
\define end-title() "
<$list filter="[{$:/HistoryList}split<title-string>splitbefore<end-title>removesuffix<end-title>reverse[]is[tiddler]]">

</$list>

see https://tiddlytools.com/#TiddlyTools%2FHistory, which adds a “Recently Visited” button to the tiddler ViewToolbar and provides a dropdown to navigate to any previously visited tiddler.

Specifically, check out the definition of the history() macro, which is a filter for getting a useful list of tiddlers visited during the current session:

\define history()
[subfilter{$:/DefaultTiddlers}] [enlist{$:/StoryList!!list}]
[{$:/HistoryList}splitregexp[\n]trim[]trim[,]removeprefix["title": "]removesuffix["]]
+[unique[]!prefix[Draft]search-replace:g[\"],["]]
\end

Note that this filter includes the $:/DefaultTiddlers and the $:/StoryList!!list, as well as parsing the contents of the $:/HistoryList. It then removes duplicates, excludes draft tiddlers (which are added to the $:/HistoryList whenever a tiddler is edited), and finally decodes any quotes that may occur within a tiddler title (and were JSON encoded when added to the $:/HistoryList)

enjoy,
-e

2 Likes

Thanks to all for the excellent discussion. I will study this later today. I’ll post my final solution once I have one.

I still don’t understand the behavior of my previous attempt, but I found if I switch from action-listops to action-setfield widget, then it works as I expect:

<$let lbrace="[" rbrace="]">
<$action-setfield $tiddler="$:/HistoryList" text={{{
  [{$:/HistoryList}jsonindexes[]last[3]]
  :map[{$:/HistoryList}jsonextract<currentTiddler>]
  :and[join[, ]addprefix<lbrace>addsuffix<rbrace>]
 }}}/>
</$let>

I used last[3] to make it easy to test. For real use a much higher number would be useful.

@HistoryBuff, the following might get what you want (I did not test):

  1. Create a global publishFilter variable containing $:/HistoryList. This way the history list will be persisted.
  2. Add a startup tiddler with the let/action-setfield code I shared above. This will prevent unbounded growth of the history list.
  3. Use <$list filter="[{$:/HistoryList}jsonindexes[]] :map[{$:/HistoryList}jsonget<currentTiddler>,[title]]"/> to display the titles in your default tiddler

You may want to add [unique[]!prefix[Draft]] to the filter as @EricShulman demonstrated in his solution.

Ok, so I ended up doing a mix of what @btheado and @EricShulman posted.

I added $:/HistoryList to the publish filter. I then created a startup tiddler with the code from @btheado which is repeated here with a limit of 20.

<$let lbrace="[" rbrace="]">
<$action-setfield $tiddler="$:/HistoryList" text={{{
  [{$:/HistoryList}jsonindexes[]last[20]]
  :map[{$:/HistoryList}jsonextract<currentTiddler>]
  :and[join[, ]addprefix<lbrace>addsuffix<rbrace>]
 }}}/>
</$let>

I then used the code from @EricShulman with the reverse operator added so that the most recent is on top:

\define history()
[subfilter{$:/DefaultTiddlers}] [enlist{$:/StoryList!!list}]
[{$:/HistoryList}splitregexp[\n]trim[]trim[,]removeprefix["title": "]removesuffix["]]
+[reverse[]unique[]!prefix[Draft]!is[missing]search-replace:g[\"],["]]
\end

I then added this code to the tiddler I wanted it displayed in:

<fieldset style="margin: 10px; padding: 5px 5px 5px 10px;">
  <legend style="font-weight: bold; padding: 0 8px 0 8px;">Most Recently Visited</legend>
  <$list filter="[subfilter<history>]">
    <$link><<currentTiddler>></$link><br>
  </$list>
</fieldset>

I changed my mind on having this in my default tiddler and, instead, added to my custom recents tiddler which I have in the sidebar. A screenshot is below showing the final product.

My last question is can the date be added like in the recently edited list? I’m guessing not, at least not without a lot of headache.

Thanks again to everyone.

I’d feel uneasy using this code exactly. It looks like it depends on the json in the history list being formatted exactly the way the navigator widget formats it. However, even the startup tiddler code I provided does not format the json in this way.

In practice it might not ever cause you problems. I’d feel better properly parsing the json using the official json operators rather than depending on the json being formatted just-so. IOW, use this in the latter part of the history macro:

[{$:/HistoryList}jsonindexes[]]
:map[{$:/HistoryList}jsonget<currentTiddler>,[title]]
+[reverse[]unique[]!prefix[Draft]!is[missing]]

rather than

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

Oops, but now I see introduction of the :map filter run would break the earlier default tiddlers and story list part of the filter. To stay compatible with that you can use something like this:

\function history.titles()
  [{$:/HistoryList}jsonindexes[]]
  :map[{$:/HistoryList}jsonget<currentTiddler>,[title]]
\end

\procedure history()
  [subfilter{$:/DefaultTiddlers}]
  [enlist{$:/StoryList!!list}]
  [history.titles[]]
  +[reverse[]unique[]!prefix[Draft]!is[missing]]
\end

<fieldset style="margin: 10px; padding: 5px 5px 5px 10px;">
  <legend style="font-weight: bold; padding: 0 8px 0 8px;">Most Recently Visited</legend>
  <$list filter="[subfilter<history>]">
    <$link><<currentTiddler>></$link><br>
  </$list>
</fieldset>

By extracting history.titles into a function, the :map will no longer be applied to the default tiddlers and storylist part of the filter.

It would require a completely different approach. Probably a custom pagetemplate which intercepted link clicks and implemented its own history mechanism.