TextEdit -- delimited list of window names.kmmacros (1.7 KB)
Expand disclosure triangle to view JS Source
(() => {
"use strict";
return Application("TextEdit")
.windows
.name()
.join("|");
})();
TextEdit -- delimited list of window names.kmmacros (1.7 KB)
(() => {
"use strict";
return Application("TextEdit")
.windows
.name()
.join("|");
})();
Or if that's literally all you're doing:
Application("TextEdit")
.windows
.name()
.join("|");
If you prefer AppleScript, it is, as usual, a bit messier – requiring more work, but still possible:
on run
tell application "TextEdit" to my intercalate("|", name of windows)
end run
-- intercalate :: String -> [String] -> String
on intercalate(delim, xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, delim}
set s to xs as text
set my text item delimiters to dlm
s
end intercalate
or
on run
tell application "TextEdit" to my intercalate(linefeed, name of windows)
end run
-- intercalate :: String -> [String] -> String
on intercalate(delim, xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, delim}
set s to xs as text
set my text item delimiters to dlm
s
end intercalate
Thanks @ComplexPoint, that JXA code is simple and sweet.
Could you elaborate on what the use strict
and return
constructions do in this case? That is not literally all that I am doing.
As I mentioned above, I'm using "|
" for testing; ultimately I want a newline there, so that I can sort and filter the list and treat items one at a time. Will .join("\n");
do it?
Thanks also for the AppleScript versions. I have the idea that eventually this will be for public consumption, so I hesitate to mix JXA and AS in the same macro suite, but what's easy is easy. Extra motivation to learn more JXA too.
In the AS code, yes I'll be using linefeed
version. Thank you!
The term "intercalate" is new to me. Googling, I found interesting examples from microbiology, geology, and biblical studies, but no coding definitions that I found lazily. Are you using it as simply an appropriate name for the operation, or is it a predefined term in AppleScript?
Thanks!
See:
an appropriate name for the operation
Yes, a user-defined function like that would work as well by any other name.
Wow. Thanks, that's a great exposition of what seems like a relatively complex subject. The language interpreter is operating at a level of abstraction that most scripters don't think about, and your explanation makes how you have to deal with that make sense.
It isn't a list delimiter you change -- it's AppleScript's text item delimiter
. It's what text is split on when you convert it to a list and what list items are joined together with when you cast a list to text. (The ", " you mention is just Script Editor's and others' visual representation of the "list item divider".)
So:
tell application "TextEdit"
set {oldTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "|"}
set winNameList to (name of every window) as text
set AppleScript's text item delimiters to oldTIDs
end tell
return winNameList
..where you are setting the text item delimiter (and saving the old one for later), getting the list of window names with (name of every window)
, casting from list to text -- using your set delimiter as the separator -- and saving in winNameList
, and resetting the text item delimiters to their original value like a polite AppleScripter should.
That is clearly the step I was not conceptualizing clearly.
I suspect I was thinking in terms of KBM, where everything is text.
Thanks!
There's really no need to do this. The important thing is to always make sure you actively set the text item delimiters
before any instance of list
to string
conversion. This should1 be something that AppleScripters do already, but not many often remember, despite it beiing the only step necessary to prevent unexpected results. Yet these same scripters cling with their lives to this obsession over restoring the delimiters back to whatever, which seems to require 5 lines of code in a lot of versions of that text replacement handler that I see as the AppleScript equivalent of my mother unplugging the microwave and toaster every time before leaving the house, and still having to check wirh my dad that she unplugged these things when they arrive at their destination. That's how pointless resetting the delimiters is.
1So, even this isn't an absolute necessity. This is all from some 20-year-old version of AppleScript that once instantiated a single process within which it executed all AppleScripts. The environment, therefore, would carry the settings left over from the previous run of one script and be in effect during the run of another script. This included the values assigned to AppleScript's text item delimiters, which someone problem-solved this (albeit in the wrong direction) by establishing a "good practice" habit of resetting the delimiters at the end of all scripts. Reasonable logic, and it caught on, but the optimal solution would have always assumed the delimiters to be some unknown value (which would cater for situations where a background script was run without being overt and didnt reset the delimiters, or one's own oversight causes the delimiters to persist through). Whereas, if one's only focus is in setting them prior to any and all list to string conversions, then it's the only measure that is entirely under one's own control, and the one making the fewest assumptions about the AppleScript environment, plus it's an action occurring only when necessary rather than as a neurosis.
Of course, none of this applies any more except in one or two very rare scenarios: Script Editor, Autimator, Script Debugger, and FastScripts all instantiate individual AppleScript processes every time a script is recompiled and executed. So you always start off with a fresh set of delimiters. KM last i checked executes its AppleScripts using osascript
, which terminates at the end of its job run. It's possible nor to have an osascript
instance destroyed, and there's one application I forget the name of that persists a single instance and recreates that 20yo situation. In fact, it might been FastScripts before the dev rejigged the entire implementation to what it is now.
Totally agree -- and thanks for explaining it better than I ever could!
If I'm writing for myself I usually don't bother resetting. But if I'm writing a snippet for someone else I can't be sure how they are going to use it, so it's a "safety first" measure.
So if someone writes:
set AppleScript's text item delimiters to "/"
repeat with eachItem in pathList
set foldersList to every text item of eachItem
-- do stuff
end repeat
....because "I've set TIDs then used them", and then wants to do further text processing in do stuff
, I don't kill their script by changing their assumed TIDs.
Yes, it would far more correct if their original script was:
repeat with eachItem in pathList
set AppleScript's text item delimiters to "/"
set foldersList to every text item of eachItem
-- do stuff
end repeat
...but since I can't guarantee that I use the reset safety belt.
Of course, I may just be excusing a 20-year habit that I really should shake
Oh no no no, that would be awful as the delimiters are being set to their present value in every iteration of the loop. So unless do stuff...
includes code that changes the delimiters as well, then you were right the first time:
If I'm handing this off to someone who intends to insert this into their script, I will quickly educate them about text item delimiters
, and hopefully instill in them from the beginning the best practice. As I would normally be walking them through the script anyway to explain what each part does (if they are novice, that is), then it actually forms an inherent part of that explanation. If they're not novice, but not seasoned either, then i guess i wouldn't give an exposition on what the script is doing, but might say "Note that this changes the AppleScript delimiters, as they're involved in splitting the filepath string into a list of its components. So just make sure that if you end up joining this list (or any other list) up later on in the script, always make sure you set the delimiters to an appropriate value right before you do so."
But yeah...it gets challenging sometimes figuring out how to say these things without sounding like a condescending twat. Sometimes i manage it, and sometimes i don't. So I don't blame you for finding a way out of having to school someone if all it takes is to bung in that ubiquitous text replacement handler at the bottom of a script or something similar.
Except, as was pointed out to me last year by one of my users, it is a very literal interpretation of my advice to them to "always set your TIDs before using them".
And yes, this all came about because they asked me for a path-splitter. A month later they asked me for a way to split text on spaces and I, stupidly, said "It's the same as the one we did before except you change the /
to a space", not considering where they would be using it. And they wrote something like:
set AppleScript's text item delimiters to "/"
repeat with eachItem in pathList
set foldersList to every text item of eachItem
-- do stuff, including
set AppleScript's text item delimiters to " "
repeat with eachItem in foldersList
set textList to every text item of eachItem
-- more stuff
end repeat
end repeat
Again, totally reasonable from their point of view as it was the same as we did before! A little too the same...
In the "before times" this wasn't such a problem as we'd usually be sitting down together and going through things, just as you describe. But we've still got a lot of people working from home -- and in this case, "home" was 10 time zones away...
So I'm afraid I've gone back to resetting TIDs, just in case, when doing snippets for others. While it's often a pair of pointless operations (which I dislike on principle) it's only a line and a half of extra code. And for me it's the same amount of typing -- TID-swapping is two of the few KM text expansions I've written!
Yeah, true, he ain't wrong.
Ach, well, if it's not going to destroy the world, then there's efficiency in simply doing what we're most comfortable with.
Getting back to the core of the OP:
I ran a series of tests with the Finder folder DeskSpaceIDs
open in the next Desktop Workspace, Finder lists it in its Windows menu.
However, running this from KBM does not work:
(Does not work)
KBM cannot "see" the window in the Desktop, possibly because System Events cannot see other Desktops. For example, after verifying in the Finder Windows menu that the folder is still open in a window, this script does not work:
(Does not work)
However, Finder knows about its own windows and can act on them in response to AppleScript. This version does work:
(Does work)
Moving the ball forward ...