Using dictionary/Lines collection variables with If Then Else conditions

Hi all, I'm struggling with, ultimately, trying to use a dictionary with an If Then Else condition. Am posting here for troubleshooting help, because for the life of me I can't work out why this macro's not working the way I'd like it to...

Background: I've recently adapted @BKannerBKannerBKannerBKanner's Favorite Finder Directories macro into my workflow. Partly so I can categorise list prompts (which I was doing before with many ludicrously long Switch action lists), but mainly just to make the macros themselves easier to maintain, given that I am definitively Not A Coder and the whole thing is held together mainly with guesswork.

Part of my existing workflow involves opening Finder windows in certain ways, depending on the file path/window title, like so:

  • if that path is already open in Finder, bring that tab to the front and reposition the window to e.g. bottom-right sixth desktop area;

  • if there's a Finder window open in that desktop area to a different path but not the desired one, open a new tab in the existing window;

  • if there's no Finder window *or* there's just no Finder window in that area (e.g. there's one in upper-right sixth), open the path in a new window.

Is all this perhaps slightly ridiculous? Yes, obviously. But it helps me keep a. my desktop and windows lists tidy, b. my sanity (in theory).

Currently, this is all dictated by a series of nested If Then Else actions, which currently have ever-growing lists of window titles hard-coded in as conditions (e.g. 'if a window title matches x, do y'). Inspired by my dictionary adventures, I'd hoped to put these window title lists into dictionaries, then use For Each to create a Lines collection with a variable (as in the FFD macro), and check each line against the currently open window titles using the per-line variable in the If Then Else action. Which seems like it should be possible?

Except... no matter where I position the If The Else action in relation to the For Each action, I can't get the macro to work properly. Specifically: if there's an existing file path open in the desired window area, it will always move to a new window instead of opening in a new tab, i.e. the exact opposite of what I want it to do. Here’s what one of them (the least chaotic) currently looks like: what does it need to be?

Screengrab of Finder window subroutine

I'm guessing this will ultimately be something simple, but after everything from regex errors (no idea) to the 'bring to front' action visibly looping for ages and *still* ultimately opening in a new window, I'm admitting defeat. Um... help, please? :folded_hands:

I don't want to sound argumentative, but I don't think it will be simple. For "starters," I don't think you know what a KM Dictionary is. Looking at your code, you seem to think it's a multi-line text string. For "seconds," there seem to be some ambiguities in your "requirements." Eg,

Does that mean if any finder window has any tab whose name starts with (or maybe is equal to?) the parameter that the user provides, or does it just refer to the frontmost Finder window? And when you say "bring that tab to the front" do you mean the front of the window, or do you mean bring the window to the front, or both?

In which desktop area? You haven't defined what "that desktop area" means. Surely it doesn't always mean "the bottom right sixth desktop area". I'm not sure if it's possible to determine "which paths are open in the bottom right sixth desktop area" of the screen. For example, what if a window is partly over that area but partly not over that area? I find it very ambiguous.

Again, I don't know how to programatically determine "if there's a window in an area." In your draft macro, I don't see anywhere in there where you attempt to determine the locations of any windows. That's probably the most complex part of the puzzle and you haven't tackled it.

Again, sorry if I sound argumentative. Normally, I'm a pretty decent person. I just don't see a well-defined problem here yet. So I don't know if I can even begin to help.

If the windows in said specified area are always the same size and position, then I think %WindowSize% and %WindowPosition% tokens could probably be useful.

Of course. But he's the one who should be specifying what he wants. So far, I'm not sure what he wants.

Sorry I wasn't clear. I quoted you, but the comment was for the OP in case they didn't know where to start to solve for that.

In your macro, you appear to read the file into the variable WindowTitleDictionaryName(s?), but then you iterate through the variable WindowTitleDictionary settings the variable WindowTitleDictionaryNam…. So that appears to be incorrect.

It seems to be the wrong way round. If you have a Dictionary of key/value pairs where the key is the window title (maybe path to target?) and the value represents "what to do with the window", then you'd search the Dictionary keys for the current window title (target?) and act according to that key's value.

So any "For Each" would be working through your Finder windows collection, not the Dictionary.

Hi all,

Apologies for the delayed update, have had work and life get in the way. Thank you everyone for your attempts to help with this! I really appreciate it, even if I’m totally barking up the wrong tree with how I’m attempting (or explaining) this - I’m definitely more flowery wordsmith than anything else :slight_smile:

To hopefully clarify (although it *is* complex, and IANAC so I'll try my best): my goal is to create a sequence to keep Finder tabs with certain parent folders grouped together within one Finder window; and keep tabs that don't have any of these parent folders grouped in another window.

This will allow me to have open and navigate multiple tabs in one project folder, in one window, without multiple tabs open to the same path, or multiple windows hiding behind each other.

This sequence ultimately:

a. checks if any open Finder tab's title either matches the target file path, starts with it, or begins with any of a specified list of parent folder paths (e.g. '/Volumes/Creative'), brings any positive matches to the front, and (if it doesn't already exist) opens the target path as a new tab in that existing window;

b. opens a new window if there are no positive match tabs already open.

There are many conditions for how a Finder tab should be opened, depending on if a tab for the target path is already open elsewhere, if it’s at the front of Finder tabs or not; or if a tab starting with the target path is open, front of Finder tabs etc. But ‘open target path only in Finder window containing other specific tabs’ is basically the gist.

Once all this is done and the target folder path is open: a Rectangle keyboard shortcut is run to reposition the window. (I'm not using the KM Window positioning tools at all due to the MacOS bug, which has thwarted macros for me elsewhere :frowning:)

Because the whole thing is reasonably enormous, I'm looking to use categorised simple text files, read in as variables, to provide:

  1. the target file paths (to populate the prompt lists);

  2. the values of file path parent folders, which the target folder's Finder window should be grouped with.

I've totally rewritten the whole routine from scratch, and - 9 subroutines later! - I think I'm getting somewhere. However, I'm still struggling with how to search each open Finder title collection line (pulled in via Applescript and formatted into a List collection using Regex), to see if it starts with the value of any line in my parent paths lines collection.

Essentially: this, but using simple text files and Lines collections to provide the values, instead of hard-coding the values into an If/Then action.

Example of previous If/Then action

The following is my current solution, but results in too many false positives *and* false negatives:

Current For Each action checking for Finder windows starting with specified parent paths

What I think I need is a version of the solution suggested here by @peternlewis. However, whenever I try to put this into a For Each action that checks each Finder windows collection line for each parent folder collection line, the whole thing just seems to end up as an endless nest of For Each actions. And, obviously, not a working nest.

How might I go about this, please?

How are you doing this? Have you a sample result?

Do you actually need to check every tab's target? If I'm reading the above description right then every tab in a window will have the same "target prefix", so you only need to check the window's target.

In order for me to help, I would need to understand the requirements. Here's an example (i.e., the words I quoted above) of a requirement I don't understand. Only one Finder Tab can be "at front" at any moment, so how do you bring multiple positive matches to the front at the same time? (Maybe you meant to say "move any matches to the left of the Finder's tab order"?) So I thought I would peek at your code for clarification, and you have two actions in a sequence that attempt to bring two different tabs to the front, so that doesn't help me understand the requirements.

Another example is the fact that all the original requirements about checking the locations of the windows on the screen seem to have disappeared. The large majority of the original requirements have just disappeared.

Working with tabs in Finder is not easy for KM, I think, even with AppleScript. So, for example, sorting the tabs in a Finder window alphabetically (which is not what you asked for, but is mentioned as an example problem working with tabs) looks like an EXTREMELY difficult problem. I am not scared off by difficult problems, but if I understand what you want, the majority of this work will have to be written by AppleScript, and it may execute very slowly, which you may not like either. How many seconds of time are you willing to wait for a solution to complete? 5 seconds? 10 seconds? 60 seconds?

Especially not with AppleScript -- as far as Finder's AS Dictionary is concerned, tabs have yet to be invented!

If we can assume that all tabs of a window share the same "target prefix" then we can ignore all but the frontmost tab of each window -- then OP has a choice of flickering through the windows to use KM's %FinderInsertionLocation% token, or "invisibly" creating a list of window target paths using AS:

tell application "Finder"
	set theList to every window's target as alias list
end tell
repeat with eachItem in theList
	set contents of eachItem to POSIX path of eachItem
end repeat
return theList

Good point. Your points are always good.

But I have a few tricks up my sleeve. For example, if a Finder window has no tabs, that can be detected by a KM condition. I will demonstrate that trick, plus some OCR magic, in the following macro, which displays (for demo purposes) a numbered list of all the names of all your Finder tabs in the progress bar window.

This macro has several limitations of course, but it's simply an example of how we can use alternative techniques offered by KM when even Applescript doesn't give the necessary tools.

Finder Tab Listing Macro (v11.0.4)

Finder Tab Listing.kmmacros (6.7 KB)

Could you explain how you're doing that?

I've always used the availability of the "Window" -> "Move tab to new window" menu item, but if your method is quicker or more reliable I'll quickly jump ship.

To be clear -- Finder's dictionary doesn't know about tabs, but that doesn't stop us from using AS to get some information about them. Like tab names:

set AppleScript's text item delimiters to linefeed
tell application "System Events"
	tell tab group 1 of window 1 of process "Finder"
		return name of every radio button as text
	end tell
end tell

But OP needs targets, not names.

There was a line in my macro that does that. The line was, "If a button with the name new tab is enabled." I tested it, and it seems to work fine.

Then it must be an OS or settings difference -- that button is always enabled for me (running Sequoia):

That's odd. I'm on Sequoia. I don't know what I did to make it work differently for me than for you. Perhaps it was you who did something to your Sequoia.

Just to be sure, please try running this simpler macro, and open a finder window, then add and remove some tabs until you have only one tab left.

Finder Tab Listing Macro (v11.0.4)

Finder Tab Listing.kmmacros (4.7 KB)

STOP THE PRESS - SORRY, I'M RUNNING TAHOE. I FORGOT. That must be the reason.

I'm sorry for forgetting that my OS is now Tahoe. The reason I realized my error was that your window didn't have the new liquid glass format, and I wondered why that was. Then I realized my error. Hey if Tahoe's Finder behaved differently now, perhaps a wizard like you can find more AppleScript dictionary support in Finder on Tahoe.

Nope -- it's a setting.

If Finder's View -> Show Tab Bar is ticked you always see the tab bar and the associated "+" button. If it isn't then you'll only see the tab bar and button once you have opened/added a tab in that window.

I must have turned it on at some stage -- odd, since I never use tabs if I can help it!

As for AS support for Finder tabs -- they haven't bothered adding in the 12 years since tabs were introduced, so I'd be amazed if they did now! More likely to come as a side effect of Shortcuts or App Intents support, IMO.

1 Like

I'm sure I'm not following the overall intent of the OP's request.

Here,however, are a few recipes that work on my Mojave set up.

Maybe they can help, since from what I can gather avoiding scripting maybe difficult--particularly with dealing with tabs.

Also,

Some of the recipes are a bit unconventional, but might execute a bit more quickly.

  • Paths of finder windows without looping thru AppleScript objects

EDIT: Turns out this one-liner works just as well but is likely no faster than @Nige_S version, since alias list is NOT AppleScript object:

use framework "Foundation"

tell application id "com.apple.finder"	
	set thePaths to ((current application's NSArray's arrayWithArray:(target of windows as alias list))'s valueForKeyPath:"path") as list
end tell
return thePaths -->list of posix paths
Verbose Version
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

--get file url paths of finder windows

tell application "Finder"
	set furlStrings to URL of target of windows
end tell

--convert to posix paths ie. /Users/username/folderpath
set fURLS to current application's NSMutableArray's array()
repeat with aFurl in furlStrings
	(fURLS's addObject:(current application's NSURL's URLWithString:aFurl))
end repeat
set paths to (fURLS's valueForKeyPath:"path") as list
  • Query a window by path
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

--query a window whose target is  the second item in a path collection
set aPath to item 2 of paths

--convert the posix path back into a furl string
set aFurlString to (current application's NSURL's fileURLWithPath:aPath)'s absoluteString() as text


--Make the found window the first window
tell application id "com.apple.finder"
	set theWindows to Finder windows whose URL of target is aFurlString
	set the index of item 1 of theWindows to 1
end tell

Tab groups:

Get all windows with tabs:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

--query windows with tabs and get the paths of the first window of the results
set tabPaths to {}
tell application id "com.apple.systemevents" to tell application process "Finder"
	tell (windows whose role description of UI elements contains "tab group")
		if (count) > 0 then
			set tabPaths to description of radio buttons of tab group 1 of item 1
		end if
	end tell
end tell
return tabPaths --a list of posix paths

Get the paths of tabs of a specific window

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set tabPaths to {}
tell application id "com.apple.systemevents" to tell application process "Finder"
	tell window 1
		if role description of UI elements contains "tab group" then
			set tabPaths to description of radio buttons of tab group 1 of item 1
		end if
	end tell
end tell
return tabPaths --a list of posix paths

Addendum:
This last snippet works provided user has paths in window title turned on.
The terminal command would be:

defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES
killall Finder

https://www.idownloadblog.com/2015/12/07/how-to-full-file-path-mac-finder-window/

1 Like