Touch Bar buttons for switching to recently-viewed Safari tabs

I thought this setup I have might be useful to others. In Safari, I have Touch Bar buttons that essentially act the same as the app switcher, but for tabs — so, the currently open tabs are ordered by how recently I’ve viewed them, and I can tap on any of the buttons to switch to that tab. You can have as many of these as you want — more will mean that you can switch to tabs you were at farther back in the past.

Here’s an example (in between the app switcher and colored buttons):

In this example, I have 7 tabs open, so this shows the 6 that aren’t active. I’ve set these buttons to have a small font size (11), no space between them, and a corner radius of 0 (except on the left of the first one), although you might want to do something different.

Preset file:

Recent Safari Tabs v1-0-5.bttpreset (15.9 KB)

While the original issue of appearing/disappearing is no longer a problem, it now seems that sometimes when I switch away from Safari, I’ll be returned back immediately, and so occasionally have to make one or two tries to leave the app. I’m not sure if that will be an issue for others.

(Original post, with a more complicated version)

Whenever I’ve used these, I’ve had an issue where buttons repeatedly disappear and reappear, seemingly at random. It makes browsing distracting and also means that I can’t be sure which button I’m about to tap, so I’ve unfortunately had to disable these buttons most of the time. So, if anyone tries this setup, I’m curious whether you experience this issue, and if so, whether you are able to find the reason it’s happening (since I haven’t been able to).

To make this work, I have a text file which stores a list of the names of all the tabs I have open (including the active one), in order of how recently they were open. All of the buttons access this list to display the tab names and to switch to the tab when pressed, and the first button also serves the purpose of updating the list.

Here’s the preset:

Recent Safari Tabs.bttpreset (15.0 KB)

You’ll have to change every instance "[insert location of file]" to point to the actual file you’re using to store the tabs.

Each button is a “Run Apple Script and Show Return Value” widget. All of them have the following AppleScript to display the name of the tab (which runs multiple times a second so they will stay updated when I open, close, or switch tabs):

set fileRef to POSIX file "[insert location of file]"
set tabFile to (read fileRef as «class utf8»)
--All the tabs in the list, in order of how recently I visited them:
set tabs to paragraphs of tabFile

--The position in the tab list that this button represents
--(1 is the current tab, 2 is the most recent other tab, etc.):
set tabNum to 5 --change the number for each button; I started with 2
--The maximum number of characters that will be displayed on the button:
set dispLen to 10
--If there aren’t enough tabs for this button to be used, hide it:
if length of tabs < tabNum then
	return ""
end if
--Get the name of this tab and cut it to the desired length:
set t to item tabNum of tabs
if length of t > dispLen then
	set t to (characters 1 thru dispLen of t) as string
end if
--Remove spaces from the end:
repeat while character -1 of t = " "
	set t to (characters 1 thru -2 of t) as string
end repeat
--Return the formatted tab name:
return t

The first button, which manages the list of tabs, has this in addition to the above:

--Every open tab:
tell application "Safari" to set openTabs to name of every tab in window 1
--The active tab:
tell application "Safari" to set currentTab to name of current tab of window 1
--If there have been any new tabs opened, add them to the list:
repeat with t in openTabs
	if tabs does not contain t then
		set tabs to {t as string} & tabs
	end if
end repeat
--If there have been any tabs closed, delete them from the list:
set tabs_ to {}
repeat with t in tabs
	if openTabs contains (t as string) then
		set tabs_ to tabs_ & {t as string}
	end if
end repeat
set tabs to tabs_
--Find the index of the active tab in the list:
set pos to 1
repeat with i from 1 to length of tabs
	if item i of tabs = currentTab then
		set pos to i
		stop
	end if
end repeat
--If it’s not at the top, move it to the top
if pos ≠ 1 then
	if pos = length of tabs then
		set tabs to {item pos of tabs} & items 1 thru (pos - 1) of tabs
	else
		set tabs to {item pos of tabs} & items 1 thru (pos - 1) of tabs & items (pos + 1) thru end of tabs
	end if
end if
--Create the string to update the file, and update the file:
set tabString to ""
repeat with t in tabs
	set tabString to tabString & (t as string) & "
"
end repeat
set tabString to (characters 1 thru -2 of tabString) as string
set eof of fileRef to 0
write tabString as «class utf8» to fileRef

Then, every button runs the following when tapped:

set fileRef to POSIX file "[insert location of file]"
set tabFile to (read fileRef as «class utf8»)
--All the tabs in the list, in order of how recently I visited them:
set tabs to paragraphs of tabFile
--The name of this tab (change the number for each button):
set t to (item 5 of tabs) as string
--Find the index of this tab in Safari, and switch to it:
tell application "Safari"
	repeat with i from 1 to number of tabs in window 1
		if name of tab i of window 1 = t then
			set current tab of window 1 to tab t of window 1
		end if
	end repeat
end tell

Again, every time I use this, there’s the issue of buttons that keep flashing in and out of existence (even though the list itself does not change). So, it may or may not work for you.

Would you mind linking a preset with these widgets?

This would ensure an easier import :wink:

Yes, I will — sorry about that, I’m new to this forum and still figuring out how sharing presets works. The preset I have here has 6 buttons, but you can add more/remove them. You’ll have to replace "[insert file location here]" with the location of the file you’re using to store the tabs.

Cool!

Just a note -
BTT supports storing variables from applescript. I think it would be better to store the data in BTT variables instead of a seperate file! Would be much neater, and possibly more efficient while also maybe fixing your diappearing issue.

Have a read, especially the variable function explanations after the basics:
https://docs.bettertouchtool.net/docs/apple_script.html

Yes, I agree that would be better! If I’m remembering correctly, that was added recently, and I made this before that was added. So, I can update it sometime; when I do, I can post it again.

1 Like

Okay, here’s an updated version:

Recent Safari Tabs.bttpreset (14.9 KB)

It also looks like it does not have the disappearing issue, which is nice.

1 Like

Great! Will try it soon.

P.S. You might want to review your top post and edit it. Maybe add a “v2” section?

If it works well, could I merge this as a safari widget in my public preset “AquaTouch” ? You’ll be credited, of course.

All right, I just added that. And sure, please go ahead and add it to AquaTouch if you’d like.

1 Like

I seem to be getting this error:

I think this is because my set is new and I haven't had any tabs loaded into the variable yet. Would you know of a fix?

Note: 'Tab 1' seems to be missing from the preset

Yes, I was wondering if that might happen, since it happened to me. To fix it, I went into Script Editor and ran a script once that set it to have some arbitrary value, and it worked from then on. However, I imagine there’s a better way that doesn’t require something like that. How about this?

Recent Safari Tabs.bttpreset (15.5 KB)

Also, I intentionally don’t have anything called “Tab 1” — I’m naming the buttons after the lines in the file, and the first line refers to the current tab. However, I guess it would make more sense to name them 1, 2, 3 instead of 2, 3, 4.

You should version your presets. Add a 'v1.0.0' to keep track of which file is which.

+1.0.0 for mega updates with complete changes and rewrites.
+0.1.0 for a small amount of new features.
+0.0.1 for bugfixes/stability improvements.

Suggest:
Initial release: v1.0.0
Change to BTT Variables: v1.0.1
'Can't get paragraph' Bugfix: v1.0.2

I'll check your fix soon.

Yes, thanks. Again, I’m still new to sharing presets; sorry that I’ve had to figure things out along the way.

it's OK, We've all gotta start somewhere! :wink:

I got the preset working and thus I think i've fixed your bugs. Take a look:

Open the [Tab 1] widget especially.
RecentViewdSafariTabs v1-0-3 (yyuuiko edit).bttpreset (17.9 KB)

Yes, thanks, it looks like that will fix it. (I can’t check for myself because that bug only appears once and I already fixed it, but I imagine that your fix will work).

I noticed that the second button (“Tab 2”) would switch to the second most recently viewed tab (Tab 3) when pressed, so I fixed that:

RecentViewdSafariTabs v1-0-4.bttpreset (17.4 KB)

I don’t currently know what I might use the Tab 1 button for (since I know what tab I’m on, and already have a button that switches to the most recent tab), so I think I might continue to use a version that doesn’t show the current tab until I figure out what I might like that button to do. (I’ll call that 1.0.5 and link it in the original post.)

Also, I have still been having the issue where, occasionally, when I switch away from Safari to another app, Safari becomes active again, and I have to try a few times. I imagine that some part of this preset requires Safari to be active, but I don’t yet know which part.

Ah, there was this problem over at VLC as well. this is probably caused by the script running after safari is in the background.

E.g:

Safari is open
buttons process...
Safari has been closed
Buttons continue processing
Buttons need to ask safari for data
Buttons open safari to do this
Buttons get their data

You probably need to wrap an “if safari is frontmost” kind of code (not sure how it actually is) around all the buttons.

Yeah, that’s what I was wondering. I’ll try something out soon, and see over a day or so if the issue persists.

1 Like