Close all tabs matching a path wildcard

Overview

This scripts adds a new command to Opus: CloseAllTabs

The CloseAllTabs command takes a path or wildcard and will close all folder tabs which match. Listers will be closed entirely if all their tabs match.

For example, CloseAllTabs X:\* will close all folder tabs in or below X:\.

This can be useful if you just want to clean up a lot of folder tabs at once, or before unmounting an encrypted drive which was mounted as non-removable (where a tab pointing at the drive may mean the drive is considered in-use).

There is also an alternative version of the script (CloseAllTabs2) which doesn't support wildcards, but will work with aliases like /trash to allow you to close all tabs showing the Recycle Bin, and similar.

Downloads:

CloseAllTabs.osp (1.56 KB) -- Wildcard version. Opus 11.4 or above.

CloseAllTabs2.osp (1.4 KB) -- Alias version. Opus 13 or above.

(The .osp file is really a zip containing the script. Change the extension to .zip and you can extract the .vbs file inside and open it in any text editor. You can drop .vbs scripts into the Opus script list directly, without creating an .osp file; the only reason .osp was used here is to make it easier for you to download, since .vbs files are typically blocked.)

Installation:

Opus 13 or above:

  • Open Settings / Scripts, download the desired script, and drag it to the list.

Older versions:

  • Open Preferences / Toolbars / Scripts, download the desired script, and drag it to the list.

History (Wildcard version):

  • v1.1 (24/Apr/2014): Better handling of \ at the ends of paths.
  • v1.0 (22/Apr/2014): First release

History (Alias version):

  • v1.2 (11/Apr/2024): Partial re-written to support aliases like /trash. Matches both the specified folder and sub-folders, without requiring explicit wildcards. (Does not support wildcards at all!).

Usage:

Once installed, a new CloseAllTabs or CloseAllTabs2 command will be available in the Button Editor, Hotkey Editor, and so on.

The CloseAllTabs command takes a single argument, which is the path or wildcard you wish to close. As usual, use quotes if the argument contains spaces.

CloseAllTabs "C:\Program Files" -- Close all tabs showing C:\Program Files.
CloseAllTabs C:\* -- Close all tabs showing C:\ or folders below C:\.
CloseAllTabs C:\*\* -- Close all tabs showing folders below C:\ but not C:\ itself.

The CloseAllTabs2 command is similar, but it doesn't support wildcards. Instead, it automatically matches sub-folders of any path you specify. It also support aliases like /trash to match special folders like Recycle Bin.

CloseAllTabs2 C:\Program Files -- Close all tabs in or below C:\Program Files.
CloseAllTabs2 /trash -- Close all tabs showing Recycle Bin.

The script itself:

If you just want to use the script, download it above.

The script code is reproduced here for people looking for scripting techniques on the forum.

Wildcard version:

option explicit

' Close All Tabs
' (C) 2014 Leo Davidson
' 
' This is a script for Directory Opus.
' See http://www.gpsoft.com.au/DScripts/redirect.asp?page=scripts for development information.

' Called by Directory Opus to initialize the script
Function OnInit(initData)
	initData.name = "Close All Tabs"
	initData.desc = "Close all tabs, in all listers, with paths matching a wildcard"
	initData.copyright = "(C) 2014 Leo Davidson"
	initData.version = "1.1"
	initData.default_enable = true
	initData.min_version = "11.3.1"

	Dim cmd
	Set cmd = initData.AddCommand
	cmd.name = "CloseAllTabs"
	cmd.method = "OnCloseAllTabs"
	cmd.desc = "Close all folder tabs, in all listers, with paths matching a wildcard."
	cmd.label = "Close All Tabs"
	cmd.template = "PATH"
	cmd.icon = "closetab"
End Function

' Helper function
Function TerminatePath(p)
	TerminatePath = p
	If (Len(TerminatePath) > 0) Then
		Dim c
		c = Right(TerminatePath,1)
		If (c <> "\" And c <> "/" And c <> "*" And c <> "?") Then
			TerminatePath = TerminatePath & "\"
		End If
	End If
End Function

' Implement the CloseAllTabs command
Function OnCloseAllTabs(funcData)

	' The path argument is required, else we don't know which tabs to close.
	If (Not funcData.func.args.got_arg.path) Then
		OnCloseAllTabs = True ' Signifies failure
		Exit Function
	End If

	' Create a wildcard out of the path argument. This will be used to test each tab's path.
	Dim wildPath
	Set wildPath = DOpus.FSUtil.NewWild(TerminatePath(funcData.func.args.path), "d")

	' We can't close listers or tabs while enumerating them, as it causes the enumeration to go wrong.
	' We also need to separately handle the case where the entire lister is to be closed, as closing the last tab
	' via Go TABCLOSE won't do anything.

	' So, we build up a Command object with a line to close each tab we want to close (only those from listers where at least one tab is not closed)
	' and we also build up a vector of Listers which we want to close entirely (those where every tab is to be closed, with none left).
	' After we finish enumerating tabs and listers, we run the command to close the tabs, then loop through our vector of Listers to close those as well.

	Dim anyTabs
	anyTabs = False

	Dim allTabsInLister

	Dim lister
	Dim tab

	Dim cmd
	Set cmd = DOpus.CreateCommand

	Dim tabsInLister
	Set tabsInLister = DOpus.NewVector

	Dim listersToClose
	Set listersToClose = DOpus.NewVector
	
	For Each lister in DOpus.listers

		allTabsInLister = True

		For Each tab in lister.tabs
			If (wildPath.Match(TerminatePath(tab.Path))) Then
				' This tab needs to be closed.
				tabsInLister.push_back tab
			Else
				' At least one tab in this lister is not being closed.
				allTabsInLister = False
			End If
		Next

		If allTabsInLister Then
			' All tabs in the lister are being closed, so we will close the whole lister instead.
			listersToClose.push_back lister
		Else
			' Only some of the tabs in the lister are being closed, so add them to the command.
			For Each tab in tabsInLister
				anyTabs = True
				cmd.AddLine "Go TABCLOSE " & tab
			Next
		End If

		tabsInLister.clear
	Next

	If anyTabs Then
		' Run the command to close all the tabs (except ones where the whole lister will be closed).
		cmd.Run
		' Clear the Command object's lines, so we can re-use it.
		cmd.Clear
	End If

	For Each lister in listersToClose
		' Close each of the listers that need to be closed.
		cmd.SetSourceTab lister.ActiveTab
		cmd.RunCommand "Close"
	Next

End Function

Alias version:

option explicit

' Close All Tabs
' (C) 2014-2024 Leo Davidson
' 
' This is a script for Directory Opus.
' See http://www.gpsoft.com.au/DScripts/redirect.asp?page=scripts for development information.

' Called by Directory Opus to initialize the script
Function OnInit(initData)
	initData.name = "Close All Tabs (alt)"
	initData.desc = "Close all tabs, in all listers, which are in or below a specified path."
	initData.copyright = "(C) 2014-2024 Leo Davidson"
	initData.version = "1.2"
	initData.default_enable = true
	initData.min_version = "13.0.0"

	Dim cmd
	Set cmd = initData.AddCommand
	cmd.name = "CloseAllTabs2"
	cmd.method = "OnCloseAllTabs2"
	cmd.desc = "Close all tabs, in all listers, which are in or below a specified path."
	cmd.label = "Close All Tabs (alt)"
	cmd.template = "PATH"
	cmd.icon = "closetab"
End Function

' Implement the CloseAllTabs2 command
Function OnCloseAllTabs2(funcData)
	' The path argument is required, else we don't know which tabs to close.
	If (Not funcData.func.args.got_arg.path) Then
		OnCloseAllTabs = True ' Signifies failure
		Exit Function
	End If

	' We can't close listers or tabs while enumerating them, as it causes the enumeration to go wrong.
	' We also need to separately handle the case where the entire lister is to be closed, as closing the last tab
	' via Go TABCLOSE won't do anything.

	' So, we build up a Command object with a line to close each tab we want to close (only those from listers where at least one tab is not closed)
	' and we also build up a vector of Listers which we want to close entirely (those where every tab is to be closed, with none left).
	' After we finish enumerating tabs and listers, we run the command to close the tabs, then loop through our vector of Listers to close those as well.

	Dim anyTabs
	anyTabs = False

	Dim allTabsInLister

	Dim lister
	Dim tab

	Dim cmd
	Set cmd = DOpus.CreateCommand

	Dim tabsInLister
	Set tabsInLister = DOpus.NewVector

	Dim listersToClose
	Set listersToClose = DOpus.NewVector
	
	For Each lister in DOpus.listers

		allTabsInLister = True

		For Each tab in lister.tabs
			If (DOpus.FSUtil.ComparePath(tab.Path, funcData.func.args.path, "p")) Then
				' This tab needs to be closed.
				tabsInLister.push_back tab
			Else
				' At least one tab in this lister is not being closed.
				allTabsInLister = False
			End If
		Next

		If allTabsInLister Then
			' All tabs in the lister are being closed, so we will close the whole lister instead.
			listersToClose.push_back lister
		Else
			' Only some of the tabs in the lister are being closed, so add them to the command.
			For Each tab in tabsInLister
				anyTabs = True
				cmd.AddLine "Go TABCLOSE " & tab
			Next
		End If

		tabsInLister.clear
	Next

	If anyTabs Then
		' Run the command to close all the tabs (except ones where the whole lister will be closed).
		cmd.Run
		' Clear the Command object's lines, so we can re-use it.
		cmd.Clear
	End If

	For Each lister in listersToClose
		' Close each of the listers that need to be closed.
		cmd.SetSourceTab lister.ActiveTab
		cmd.RunCommand "Close"
	Next

End Function

That's something I was about to script as well, so I like that very much! o) Thank you for sharing this!

It is just perfect for the folder-context menu I think (as long as the tab-context cannot be edited o).

I think there's an option to make the tab show the folder context menu when you right-click the label. (With the icon part still showing the menu the whole tab shows by default.)

Yep, thanks! I'm using that option already and it's great to have. An extendable tab-context would be a nice addition though, as there is a "Close Tab" entry already in there, and the new "CloseAllTabs" would feel very comfortable in there too, I think. But now let's stay ot. o)

This is the new "Close" menu I added to "All Folders"-filetype. I had some trouble at first, so here is an example code which seems to work fine for me. It first closes all child-tabs (tabs showing subfolders of the current tab-folder) and after that, closes all tabs, showing the same folder on which the code was run on. Maybe Leo, it makes sense to trim the trailing slash automatically in the script, to get rid of the noterm-thing?

@nofilenamequoting CloseAllTabs "{f|noterm}\*" CloseAllTabs "{f|noterm}"

I've uploaded a new version (v1.1) that takes care of \ at the end of paths, so the noterm should no longer be needed in your example.

(Remember to change {f|noterm}* to {f}* without the extra \ if you want to remove the noterm from that line.)

Thank you! That works! o)
Being able to close a tab and all tabs showing subfolders in one go is a nice addition as well (maybe it was possible already, but there was no example on how to do it). o)

I'm looking for a button that does "Close all tabs except [the ones specified]". Is this easily possible with any built-in command or is a script like the one above required?