What is Best Method to Get List of Names of Finder Selection?

finder
foundation
asobjc

(Jim Underwood) #1

Surely this has been asked and answered a thousand times by now.
But after extensive searching, I’ve not found a good answer.

Would one of you AppleScript gurus mind sharing your solution?

Here’s what I have, which works fine for small selections. But I suspect it would be slow for large selections. It just seems like we should be able to get this with one command.

tell application "Finder"
  set itemList to the selection
  
  ## FAILS ##
  --set itemNameList to name of every item in Selection
  
  set itemNameList to my getItemName(itemList)
  
end tell

on getItemName(pFinderItemOrList)
  if (class of pFinderItemOrList is list) then
    set nameList to {}
    repeat with iItem in pFinderItemOrList
      set end of nameList to (name of iItem)
    end repeat
    return nameList
  else
    return name of pFinderItemOrList
  end if
end getItemName

TIA.


(Christopher Stone) #2

Hey JM,

That’s what testing is for. :wink:

I have a number of folders in my ~/test_directory/ for just such testing:

Many_Files_25
Many_Files_50
Many_Files_250
Many_Files_500
Many_Files_1000
Many_Files_6000
Many_Folders

You can’t. The selection in the Finder is not really an object you can work with. It’s basically a command that returns a result.

NOTE: – ALWAYS get the selection as alias list (or as text). The bare form produces Finder references and is significantly slower.

Testing with a selection of 500 items:

----------------------------------------------------------------------

set nameList to {}

tell application "Finder"
   set fSelection to selection as alias list
   
   repeat with f in fSelection
      set end of nameList to name of f
   end repeat
   
end tell

--> 3 seconds (with as alias list)
--> 9+ seconds (without as alias list)

----------------------------------------------------------------------

set AppleScript's text item delimiters to linefeed

tell application "Finder"
   set fSelection to selection as text
end tell

set nameList to paragraphs of cng("^.+:([^:]+):?$", "\\1", fSelection) of me

# OR using the Satimage.osax instead of paragraphs
# set nameList to fnd("^\\S.*$", nameList, true, true) of me

--> 0.2 seconds (without converting to list)
--> 0.95 seconds (with converting to list)

----------------------------------------------------------------------
--» HANDLERS
----------------------------------------------------------------------
# REQUIRES: Satimage.osax
----------------------------------------------------------------------
on cng(_find, _replace, _data)
   change _find into _replace in _data with regexp without case sensitive
end cng
----------------------------------------------------------------------

-Chris


(Phil Stokes) #3

Am I missing something here.

What’s wrong with this?

tell application "Finder"
	set s to (get selection)
end tell

Aside from the fact that I’d avoid working with the Finder whenever possible.


(Jim Underwood) #4

Chris, I was hoping that you might respond to this. :wink:

Thanks for the definitive answer. This should be posted in a very prominent place somewhere. It is a basic tip that all users of AppleScript should be aware of.

I keep thinking that we (all AppleScript users) really need an AppleScript Wiki that is well supported by guys like you, Shane, Mark, and others here and on the ASUL.

I’d be glad to serve as the admin of such a wiki if you guys are interested.


(Jim Underwood) #5

Phil, thanks for the suggestion.
I believe that your script returns a list of Finder objects.
I was looking for just a list of names.


(Phil Stokes) #6

Right, sorry. Missed the distinction.

I only have a variant on yours, but essentially the same thing, looping through the selection and getting the name property.

set nameList to {}
tell application "Finder"
	set s to (get selection)
	repeat with i from 1 to count of s
		set this_item to item i of s
		set end of nameList to this_item's name
	end repeat
end tell

(Christopher Stone) #7

I already did that, but I flubbed the timing info.

I think the original numbers reflected just the time it took to get the selection.

I’ve changed these to show the run-time of the full script.

The fastest method of getting the selection is to get it as text.

I suspect that using ASObjC will be as fast or faster than using the Satimage.osax.

-Chris


(Phil Stokes) #8

I don’t have satimage to compare, but try this:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
property NSString : a reference to current application's NSString
# property NSArray : a reference to current application's NSArray

tell application "Finder"
	set fSelection to selection as text
	set parentF to insertion location as text	
end tell

set aString to NSString's stringWithString:fSelection
set anArray to (aString's componentsSeparatedByString:parentF) as list


Of course, speed isn’t the only factor - it also depends on what the user wants to do with that list. One thing I don’t like about getting the selection as text is you end up with the colon separated path forms, which might slow you down later if you need to convert them to something else.


(Shane Stanley) #9

Quite so. I’m struggling to think why you’d want just the names in the real world.

Especially as it’s possible the selected items aren’t in the same folder (in which case the last script will fail).


(Phil Stokes) #10

I didn’t want to bring that up because it wasn’t Jim’s question, but my initial thought here was: well, I wouldn’t use the Finder to get files names into a script in the first place, and certainly not for huge lists of them. But without knowing the purpose, it’s impossible to suggest an alternative.

Good point. Didn’t think of that.


(Jim Underwood) #11

Shane, I’m always glad to help you better understand the perspective of lesser users. :wink:

There are a number of times when I’ve needed just the list of item names.
The most recent is to show the list in a choose from list dialog.

If there is a better way to get a list of item names from the items selected in the Finder, I’m all ears. :wink:


(Shane Stanley) #12

But if you’re going to then do something with the files whose names are chosen in the dialog, you don’t need just the list of names – you need parallel lists of the names and the files, so you can match them up when the user’s choice has been made. That’s what I meant by not wanting “just the names”.

And what you intend to do with the files might well be the more important factor in how you get the original list, and hence the names, from the Finder. For example, if you intend to pass them to an application to open, then you probably want them as an alias list; if you intend to pass them to System Events, you might want them as simple paths. You certainly don’t want them as Finder references unless you’re going to be doing something with them in the Finder anyway.

I guess I’m saying that in the real world, chances are the best choice depends on what else you’re doing, because in that context you’re not really getting just the names.


(Jim Underwood) #13

OK, let’s say that is what I need.

But I need just the item names for the choose from list.
So, what solution do you propose that would allow me to do that, and then use, say the POSIX path, for the item based on the user’s choices?


(Shane Stanley) #14

Unless there are likely to be a very large number involved, Chris’s first option in the first reply should be fast enough – I don’t see any need to make it more complicated. Then you can use the POSIX path property of the alias(es) in the alias list.


(Jim Underwood) #15

Thanks, Shane, but I’m not sure you really answered my question. :wink:

While Chris’ option is faster, it is functionally the same as my original post.

I guess I thought you had some cool way of showing the user a simple list of item names, and then based on his/her selection, get the path to the item. AFAIK, the only way to do this is by determining the position in the list of the user’s choice, and then using that as an index into the path list.

Do you (or anyone) have a better method?


(Shane Stanley) #16

It’s not really the same, because it gives you a list of aliases rather than a list of Finder references. That’s a significant difference when it comes to using the results.

There’s no magic.

Pretty much. There are other ways, but they’re contrived. For example:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use theLib : script "Myriad Tables Lib" version "1.0.7"
use scripting additions

set nameList to {}

tell application "Finder"
	set fSelection to selection as alias list
	repeat with f in fSelection
		set end of nameList to name of f
	end repeat
end tell

set theInfo to swap columns and rows in {nameList, fSelection}
set theResult to display table with data theInfo row template {text, missing value} with prompt "Pick a file" with double click means OK
set theFile to item 2 of item 1 of values selected of theResult

(Jim Underwood) #17

Shane, OK, now you’re just being overly modest. :wink:
You forgot to mention the minor detail of using Myriad Tables Lib.

This is the cool solution I was looking for.
It is a very effective use of MT, that requires only one additional line of setup.

Many thanks. I can turn this into a general purpose handler that passes two lists, one for selection, and the other that is returned.

Awesome! :+1: