Lost brackets in AppleScript output in Keyboard Maestro

I have two Chrome windows open, with a few tabs in each window. I'm running the following AppleScript:
tell application "Google Chrome" to return {URL} of tabs of (windows)

When I run it in Script Editor, I get the following result:
{{{"https://pitchfork.com/", "https://overcast.fm/uploads", "https://www.facebook.com/", "https://twitter.com/i/notifications"}, {"https://slate.com/", "https://www.instapaper.com/u", "https://stackoverflow.com/"}}}

But when I run it from Keyboard Maestro, the output is:
https://pitchfork.com/, https://overcast.fm/uploads, https://www.facebook.com/, https://twitter.com/i/notifications, https://slate.com/, https://www.instapaper.com/u, https://stackoverflow.com/

As you can see, the first version contains brackets that let me see which tabs are in which window. The KM version drops those brackets, meaning that all the tabs appear in a single list.

Any suggestions for how to preserve the brackets? Or do I have to use a more complicated AppleScript to get the window index in KM?

The return result from an Execute AppleScript action is a string. So the result you get is what you get when the output value is converted into a string. For example, in Script Editor, you will get the same result with this code:

tell application "Google Chrome" to set r to {URL} of tabs of (windows)
r as string

Offhand I don't know if there is any way to have AppleScript convert your array into a formatted string. A quick search of the Internet did not reveal anything, but maybe someone more versed in AppleScript on the forum can assist. Otherwise you will need to turn your array into a string in a way that you can then properly process once you are in your macro.

You need a slightly more complicated AppleScript.
When you return an AppleScript list to KM, it will convert to text.
So, you need to do the conversion yourself to get what you want.

I'm not sure I understand exactly what you want as the end product, but this example should get you started.

Example Output

<Window#>,<Tab URL>

1,https://forum.keyboardmaestro.com/t/lost-brackets-in-applescript-output-in-keyboard-maestro/10742
1,https://regex101.com/account/all
1,https://regex101.com/r/B3q6BW/1
1,https://regex101.com/
1,https://www.google.com/search?q=site:wiki.keyboardmaestro.com%20variables
1,https://wiki.keyboardmaestro.com/token/Variable
2,http://forum.latenightsw.com/

AppleScript

tell application "Google Chrome" to set tabWinList to URL of tabs of every window

set tabList to {}
repeat with iWin from 1 to (count of tabWinList)
  set winList to item iWin of tabWinList
  repeat with tabURL in winList
    set end of tabList to (iWin as text) & "," & tabURL
  end repeat
end repeat


set AppleScript's text item delimiters to linefeed
set tabTextList to tabList as text

return tabTextList

If you return the script results to a KM Variable, say "Local_TabList", then you can use a For Each action to cycle through each Tab in the list. If the For Each loop variable is "Local__Tab", then you can get the Window # and URL like this:

image


Here's an example Macro:

Example Output

image


MACRO:   Get Chrome Tab URL List [Example]


#### DOWNLOAD:
<a class="attachment" href="/uploads/default/original/3X/b/5/b5cf3b34ee7c01179758b94c985be206d2ac37b1.kmmacros">Get Chrome Tab URL List [Example].kmmacros</a> (6.1 KB)
**Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.**

---



![image|458x1428](upload://5GlTVDzb6eNQZJIBWVCFSfSaUk8.jpg)

---

Questions?

If you change string for list in applescript snippet, it gives the tabs with brackets. Applescript will guess the kind of data you want as a result if it is not specified. Since the result is a list, that's what you get. Since KM gets you the result as string by default, maybe forcing it with "as list" would work.

Adding as list just gives the output {URL of every tab of every window of application "Google Chrome"}. Classic AppleScript.

Thanks for the replies—I think I have to iterate through the windows and tabs and store the actual index numbers in the output string.

One option is to display the output as a JSON string, by wrapping it in a generic showJSON function, yielding a Keyboard Maestro result like:

16

e.g.

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on run
    set sampleOutPut to {{{"https://pitchfork.com/", "https://overcast.fm/uploads", "https://www.facebook.com/", "https://twitter.com/i/notifications"}, {"https://slate.com/", "https://www.instapaper.com/u", "https://stackoverflow.com/"}}}
    
    return showJSON(sampleOutPut)
end run


-- GENERIC ------------------------------------------------------------------
-- https://github.com/RobTrew/prelude-applescript

-- showJSON :: a -> String
on showJSON(x)
    set c to class of x
    if (c is list) or (c is record) then
        set ca to current application
        set {json, e} to ca's NSJSONSerialization's dataWithJSONObject:x options:1 |error|:(reference)
        if json is missing value then
            e's localizedDescription() as text
        else
            (ca's NSString's alloc()'s initWithData:json encoding:(ca's NSUTF8StringEncoding)) as text
        end if
    else if c is date then
        "\"" & ((x - (time to GMT)) as «class isot» as string) & ".000Z" & "\""
    else if c is text then
        "\"" & x & "\""
    else if (c is integer or c is real) then
        x as text
    else if c is class then
        "null"
    else
        try
            x as text
        on error
            ("«" & c as text) & "»"
        end try
    end if
end showJSON

1 Like

That is exactly what my script does.

1 Like

This handler will output a string representation of almost any AppleScript object:

on str(object)
	local object
	
	try
		object as null
	on error E --> "Can’t make %object% into type null."
		set my text item delimiters to {null, "Can’t make ", " into type null."}
		text items of E as text
	end try
end str

For example:

set mylist to {{¬
	{¬
		"https://pitchfork.com/", ¬
		"https://overcast.fm/uploads", ¬
		"https://www.facebook.com/", ¬
		"https://twitter.com/i/notifications"}, ¬
	{¬
		"https://slate.com/", ¬
		"https://www.instapaper.com/u", ¬
		"https://stackoverflow.com/"} ¬
		} ¬
	}

str(mylist)

Result: "{{\"https://pitchfork.com/\", \"https://overcast.fm/uploads\", \"https://www.facebook.com/\", \"https://twitter.com/i/notifications\"}, {\"https://slate.com/\", \"https://www.instapaper.com/u\", \"https://stackoverflow.com/\"}}"

Of course, the KM output won't have the backslashes, and its output will be more like:

{{"https://pitchfork.com/", "https://overcast.fm/uploads", "https://www.facebook.com/", "https://twitter.com/i/notifications"}, {"https://slate.com/", "https://www.instapaper.com/u", "https://stackoverflow.com/"}}

2 Likes

Nice solution! I knew one of you clever scripters would have a solution to this!

1 Like

And very useful this little hack is – I use it quite often.

There used to be an OSAX that would do this prettier and with more options – the AKUA Sweets osax if I remember correctly – but it's been a dead duck since MacOS 9 was laid to rest.

As you know the Script Editor and Script Debugger use the escaped slash to demonstrate a literal quote character, since double-quotes are normally reserved characters.

If you're working in the Script Editor and want to visualize a string without the quotes you can do something like this:

on str(object)
   local object
   
   try
      object as null
   on error E --> "Can’t make %object% into type null."
      set my text item delimiters to {null, "Can’t make ", " into type null."}
      set _str to text items of E as text
      
      # To get un-escaped quotes out of the Script Editor application:
      
      # Using the clipboard:
      set the clipboard to _str
      
      # AND/OR:
      
      # Using the Script Editor itself:
      tell application "Script Editor"
         make new document with properties {text:_str}
      end tell
      
   end try
end str


set mylist to {{¬
   {¬
      "https://pitchfork.com/", ¬
      "https://overcast.fm/uploads", ¬
      "https://www.facebook.com/", ¬
      "https://twitter.com/i/notifications"}, ¬
   {¬
      "https://slate.com/", ¬
      "https://www.instapaper.com/u", ¬
      "https://stackoverflow.com/"} ¬
      } ¬
   }

str(mylist)

You can do something very similar in Script Debugger, BUT you can also change the view in SD from Standard which shows the backslash to Best which shows only the literal string.

There's also an AEPrint view which shows the raw Apple Event format.

-Chris