Monday, April 22, 2019

#51 2019-02-06 04:27:35 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5626

Re: Loading file list from a folder

Nigel Garvey wrote:

this variation



Ingenious wink


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#52 2019-02-07 07:01:38 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4852

Re: Loading file list from a folder

Shane Stanley wrote:
Nigel Garvey wrote:

this variation



Ingenious wink


Actually, this is simpler:  smile

Applescript:

use AppleScript version "2.5" -- 10.11 or later
use framework "Foundation"
use scripting additions

on listFilesIn:sourceAliasOrFile fileStub:fileStub excludedExtensions:theExtensions
   set fileManager to current application's NSFileManager's defaultManager()
   set theURLs to fileManager's contentsOfDirectoryAtURL:sourceAliasOrFile includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
   
   set thePred to current application's NSPredicate's predicateWithFormat:"lastPathComponent.stringByDeletingPathExtension ==[c] %@ AND NOT ANY %@ ==[c] pathExtension" argumentArray:{fileStub, theExtensions}
   set theURLs to theURLs's filteredArrayUsingPredicate:thePred
   return theURLs as list
end listFilesIn:fileStub:excludedExtensions:

Last edited by Nigel Garvey (2019-02-07 07:14:06 am)


NG

Offline

 

#53 2019-02-07 01:01:10 pm

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

I've downloaded this updated version, Shane. Will give it a try.

Offline

 

#54 2019-02-08 10:38:54 am

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Shane;

I tried the last routine you posted and it worked well.

I do have one other item to ask about this topic.

When using the list to open files, one can end up switching back-and-forth between default apps. This interleaving of the apps, used to open the files,seems to cause the order on the screen to not match the order in which they were opened. However; if the app calls are grouped, this appears not to be an issue.

Unfortunately; I can't think of a "fast" way to order the URL list by the app type. It would be great if there was a way to augment your routine to do this. As I'm not that familiar with the AppleScriptObjC world yet, I could use a nudge in the right direction.

Model: MacBook Pro (retina)
AppleScript: 2.9
Browser: Firefox 64.0
Operating System: macOS 10.14

Last edited by GG (2019-02-08 10:57:48 am)

Offline

 

#55 2019-02-08 03:08:20 pm

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Well...

My guess was correct. I wrote an AppleScriptObjC sorting routine, for a list of app-filename lists, to make sure that all files with the same app were grouped together. When the list of files was opened, using the default apps, the windows were stacked in the order they had been commanded to open.

It's a bit slow, but I've a lot of debug and logging code in it at present. I hope the lean version will run faster.

The following are the relevant snippets from my code (which I'll post when I have the move and size windows portion working:

Applescript:

       -- --------------------------------------------------------------------------------
       -- create a list of the app and the file it should open
       -- --------------------------------------------------------------------------------
       set theSortedList to {}
       repeat with theFile in theList -- this is the output of Shane's routine
           -- --------------------------------------------------------------------------------
           -- get the name of the default_app for the file that is to be opened.
           -- --------------------------------------------------------------------------------
           set default_app to getDefaultApp(pathExtensionFromFileReference(theFile))
           copy {theFile:(theFile as string), theApp:(default_app as string)} to the end of theSortedList
       end repeat
       
       set anArray to current application's NSArray's arrayWithArray:theSortedList
       set theDesc to current application's NSSortDescriptor's sortDescriptorWithKey:"theApp" ascending:true selector:"caseInsensitiveCompare:"
       set theDesc2 to current application's NSSortDescriptor's sortDescriptorWithKey:"theFile" ascending:true selector:"caseInsensitiveCompare:"
       set theSortedList to (anArray's sortedArrayUsingDescriptors:{theDesc, theDesc2}) as list


-------------------------------------------------------
-- code removed here for posting purposes --
-------------------------------------------------------


-- -------------------------------------------------------------
-- handler to get the default app for a given filename extension.
-- -------------------------------------------------------------
on getDefaultApp(pExtStr)
   
   -- Based on @ShaneStanley's script & enhancements
   -- http://forum.latenightsw.com/t/how-do-i-get-the-default-app/830/2
   -- 2017-11-26
   
   set thePath to (POSIX path of (path to temporary items)) & "temp." & pExtStr
   
   set nsCurApp to current application
   
   --- Create a Temp File with Extension ---
   nsCurApp's NSFileManager's defaultManager()'s createFileAtPath:thePath |contents|:(missing value) attributes:(missing value)
   
   set ws to nsCurApp's NSWorkspace's sharedWorkspace()
   
   --- Get URL of Default App for That Extension ---
   set nsAppURL to ws's URLForApplicationToOpenURL:(nsCurApp's |NSURL|'s fileURLWithPath:thePath)
   
   --- Get the FileName of the App ---
   set {nsResult, nsAppName, nsError} to nsAppURL's getResourceValue:(reference) forKey:(nsCurApp's NSURLLocalizedNameKey) |error|:(reference)
   
   --- Get Just the Root Name of the App ---
   set appName to nsAppName as text
   set appName to text 1 thru ((offset of "." in (appName as text)) - 1) of appName
   
   return appName
   
end getDefaultApp

Offline

 

#56 2019-02-08 07:16:50 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5626

Re: Loading file list from a folder

You can potentially speed it up a fair bit by eliminating duplicate calls to the expensive getDefaultApp() handler, something like this:

Applescript:

set theSortedList to {}
set appDetails to current application's NSMutableDictionary's dictionary()
repeat with theFile in theList
   -- --------------------------------------------------------------------------------
   -- get the name of the default_app for the file that is to be opened.
   -- --------------------------------------------------------------------------------
   set theExt to pathExtensionFromFileReference(theFile)
   set default_app to (appDetails's objectForKey:theExt)
   if default_app is missing value then
       set default_app to getDefaultApp(theExt)
       (appDetails's setObject:default_app forKey:theExt)
   end if


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#57 2019-02-08 10:43:24 pm

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Thank you, Shane.

I tried it out and it does work a bit quicker. I can understand what you were doing, so I guess I must be learning something (although it hasn't been easy).

Offline

 

#58 2019-02-09 05:12:17 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4852

Re: Loading file list from a folder

Also, you could adapt the getDefaultApp() handler to work with the current file instead of making a new file with the current file's extension.


NG

Offline

 

#59 2019-02-09 09:41:52 am

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Hi Shane;

Yes, I wondered about creating the temp file to find the app, since one already has a typecase in the input file. I'll give it a try.

(Have you considered querying Launch Services? I did a bit of reading and have a niggling suspicion that it mag also be able to tell one the default app. Would it be a better way? I don't know.)

Offline

 

#60 2019-02-09 10:41:21 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4852

Re: Loading file list from a folder

GG wrote:

Hi Shane;

Yes, I wondered about creating the temp file to find the app, since one already has a typecase in the input file. I'll give it a try.


My name's Nigel.  smile


NG

Offline

 

#61 2019-02-09 12:29:51 pm

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Sorry Nigel. I'm a little out of it. Not sleeping well. Thanks for your suggestion.

Offline

 

#62 2019-02-09 07:33:12 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5626

Re: Loading file list from a folder

GG wrote:

Have you considered querying Launch Services?



Launch Service has a C-style API, not Objective-C, so it's out of reach of ASObjC.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#63 2019-02-12 01:05:50 pm

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

I'm going back over the code I've extracted from the previous posts and would like to ask a question about the variables passed from AppleScript to ObjC routines.

In some code I see a step that converts AppleScript strings to "Cocoa" strings. I believe that this has been used to indicate a conversion to what the Language Reference calls, (NSString *)string

Applescript:

set cocoaString to current application's NSString's stringWithString:theFilename

However; I don't see this conversions being done in all code examples, nor for other types of AppleScript variables.

I suspect the answer lies in some form of casting of certain AppleScript data types that is going on, but I'm still learning and don't know for sure.

Can one of the skilled coders shed some light on this?

Meanwhile, I'm also going to go back and read "Everyday AppleScriptObjC" again and see if I can figure out why.

Offline

 

#64 2019-02-12 02:31:27 pm

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Ok. I've gone over the relevant section in Shane's book and understand that some conversions are done as a result of "Bridging". (Which I percieved as being "casting". Close but not the same)

So; I think I can push on with analyzing the code myself.

I would like to ask one question, because the XCode documentation seems to have changed. (I am using the documentation from Version 10.1 (10B61))

The code in one of the previous post entries uses:

Applescript:

+ (NSURL *)fileURLWithPath:(NSString *)path;

e.g.     

Applescript:

set sourceAliasOrFile to current application's class "NSURL"'s fileURLWithPath:(cocoaPathString)

The current XCode documentation defines the "same" function as:

Applescript:

class func fileURL(withPath path: String) -> URL

Does this mean that, while old form may still work, it really should be written as:

Applescript:

set sourceAliasOrFile to current application's class "NSURL"'s fileURL(cocoaPathString)

Because, it doesn't appear to work and returns an error.

Last edited by GG (2019-02-12 02:42:41 pm)

Offline

 

#65 2019-02-12 04:25:23 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5626

Re: Loading file list from a folder

The "function" is Swift code, not Objective-C.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#66 2019-02-12 07:44:29 pm

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Thanks, Shane. I had a look and can see that now. The new XCode documentation is quite different looking from what you described in your book. (No fault on your part. Things get updated by Apple.)
So; I'm just going to have to make sure that, after I do a search, I remember to select the ObjC button.

(I'm really starting to like your book. It takes you through things step by step and you seem to have anticipated many of the questions one might have. So far; between it, the XCode documentation and the Script Debugger, I've managed to get almost all the data types aligned in my project. That, and adding copious comments, has made it far easier to follow.)

Offline

 

#67 2019-02-13 06:49:11 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4852

Re: Loading file list from a folder

GG wrote:

Ok. I've gone over the relevant section in Shane's book and understand that some conversions are done as a result of "Bridging".


If I've understood your question about why some "conversions" are done explicitly and some simply "bridged", the bridged ones are invariably parameters to the "methods" used. If an AppleScript object's passed to a method, and the bridge knows how to convert it to the type the method expects, bridging takes place.

The methods themselves don't belong to the Objective-C language, but either to particular classes of object or to individual instances (objects) of those classes. So if you want to use "instance" methods, you have to create the instances first, which you do using suitable "class" methods.

In your example in post #63 …

Applescript:

set cocoaString to current application's NSString's stringWithString:theFilename

stringWithString: is an NSString class method which creates an NSString with the same value as another NSString. If the parameter theFilename is AppleScript text, it's bridged to NSString at the input to the method because an NSString is what the method expects. So this trick can be used to create an NSString version of an AS text. The NSString to which cocoaString's set is presumably a copy of the instance created by the bridge. You can use its instance methods to return information about it or to derive other data from it.


NG

Offline

 

#68 2019-02-13 08:54:56 am

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Thanks, Nigel. You understood what I was driving at.

I think I'm starting to get the hang of this now.

There's so much to learn and I really appreciate you and Shane sharing what you know.

Just a thought...
I hope one of you "Code Gurus" (when time permits) will do a tutorial in the "unscripted" section about "The need for speed or how to optimize your code". This topic needs someone with a wealth of experience with what works and what doesn't. It's pretty hard to glean that information from individual posts.

Cheers;
Gary

Offline

 

#69 2019-02-14 05:29:16 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4852

Re: Loading file list from a folder

GG wrote:

I hope one of you "Code Gurus" (when time permits) will do a tutorial in the "unscripted" section about "The need for speed or how to optimize your code".


I started to write such an article years ago, but got bogged down in the details.  wink

Basically, optimisation for speed involves developing an understanding that:
1. Things take a certain amount of time to do.
2. Some things take longer than others.
3. Some agents do things faster than others.
4. Commands to external agents take a certain amount of time to be transmitted and acknowledged.
5. Commands to external agents are one-offs to those agents they'll have their own housekeeping to do in connection with each one.
6. Every command and operator written into a script actually does something.
7. Doing things in a certain order can render some of them unnecessary (actually or statistically) or make less work for the processor.
8. AppleScript has certain quirks.

It's important not to lose sight of the fact that speed comes only a close second to the script achieving the desired result faultlessly. Many professional scripters don't have time to look into shaving an odd second or two off a script's running time (or say they don't) before delivering it to their client. It's also desirable that code be written in such a way that anyone seeking to understand it — including the original author months later — can do so with the minimum of effort.

Twenty years ago, if you wanted to use AppleScript, you had to learn the language and do the best you could with it. Nowadays, computers are very much faster and many of the old minor optimisations are practically pointless. The AppleScript philosophy that it can be used by anyone from home users to professionals has been expanded by the ability to run shell scripts and/or to call system Objective-C methods directly. Many home users will be happy just to have written something that does what they want. Many professionals will come to AppleScript already familiar with shell commands (and the languages that can be used in them) or with Objective-C. These people may be happier using what they already know and only learn enough AppleScript to allow them to do so. It could be just we enthusiasts who are still interested in the actual efficiency of our scripts.  wink

Last edited by Nigel Garvey (2019-02-14 06:06:14 am)


NG

Offline

 

#70 2019-02-14 01:25:59 pm

GG
Member
Registered: 2019-01-14
Posts: 98

Re: Loading file list from a folder

Nigel;

Thanks for your thoughts. I understand what you mean. And, within limits, I likely won't worry about a few seconds.

That said; I've found that there are certain "rules-of-thumb" that result in faster execution. I guess I'll just try different things and see what works. I don't expect to find a code optimizer for AppleScriptObjC, but I sure wish there were one. :>)

Regards;
Gary

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)