Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

AppleScript action improvements. Fixes #1023 #1048

Merged
merged 11 commits into from Feb 7, 2013

Conversation

Projects
None yet
6 participants
Owner

pjrobertson commented Aug 14, 2012

This adds an open files method to Quicksilver's scripting library, for dealing with files.

At the moment, you can send a file from the dSelector to an AppleScript by writing in the AppleScript:

on open myDObject

This is somewhat misleading though, as this just uses the AppleScript standard open action with things piped from Quicksilver, meaning that doing on open myDObject with myIObject builds fine in the AppleScript Editor, but it doesn't run.

Adding a new open files method means that you now use

on open files myDObject with myIObject in AppleScript (the on open myDObject method still works for backwards compatibility), meaning there's much less ambiguity, since open files is defined by QS and will validate the AppleScript.

Along with this, I've fixed a small bug whereby if an AppleScript contained something like tell Application SomeApp to open, Quicksilver would think it was a file AppleScript, even if it started with on process text

An example of how to use this action:

    using terms from application "Quicksilver"
        on get argument count
            return 2 -- if you want the third pane to be filled, otherwise return 1 (or leave this handler out)
        end get argument count
        on open files dObject with iObject  
            tell application "Finder" to move file dObject to folder iObject
        end open files
    end using terms from

Any update on if/when this will be merged? I'd very much appreciate this feature.

Owner

pjrobertson commented Oct 15, 2012

@daniels220 - we're at the mercy of the other Quicksilver developers (most likely @skurfer ;-) ) on getting this merged.
Hopefully soon... :)

Owner

skurfer commented Oct 15, 2012

Careful what you wish for. I don't care if AppleScript works or not, so I'm as likely to merge it unseen as anything. ;-)

Seriously, I wonder if @ddlsmurf has time to look it over. He'd be much more qualified to render an opinion.

Owner

skurfer commented Oct 16, 2012

Does this mean on open theFile no longer works, or just that there's an additional (better) way? I was trying to save your example script to ~/Library/Application Support/Quicksilver/Actions using that AppleScript everyone has to set the location of the Open/Save Dialog and it didn't work. So, hey look, I do care! ;-)

Update: The console shows

2012-10-16 14:29:17.194 Quicksilver[26836:c817] Perform AppleScript Action Error: "NSAppleScriptErrorNumber" = -1708;
Owner

skurfer commented Oct 16, 2012

Trying to move a file to the Desktop using your example script, I get:

2012-10-16 14:40:41.210 Quicksilver[28268:900f] Perform AppleScript Action Error: "NSAppleScriptErrorMessage" = "Finder got an error: Can\U2019t get folder \"/Users/rob/Desktop\".";
"NSAppleScriptErrorRange" = NSRange: {0, 0};
"NSAppleScriptErrorBriefMessage" = "Can\U2019t get folder \"/Users/rob/Desktop\".";
"NSAppleScriptErrorNumber" = -1728;
"NSAppleScriptErrorAppName" = "Finder";
Owner

pjrobertson commented Oct 16, 2012

Hmm... I'll take a look. Thanks! :D

Owner

pjrobertson commented Oct 16, 2012

OK I've added a new commit that fixes the problem. It must have slipped through at some point.

Also note that the AS in the initial comment will give an NSLog when run, since it doesn't return anything. Adding return missing value (AS's equivalent of return nil) fixes this log (which doesn't cause any real problems)

    using terms from application "Quicksilver"
        on get argument count
            return 2 -- if you want the third pane to be filled, otherwise return 1 (or leave this handler out)
        end get argument count
        on open files dObject with iObject          
            tell application "Finder" to move file dObject to folder iObject
            return missing value
        end open files
    end using terms from
Owner

skurfer commented Oct 16, 2012

OK, that seems to work (if you build QS with the changes, recompile the script, then relaunch QS). It should probably return the file in its new location (if such a thing is possible), but that's obviously an issue with this particular script.

I still can't use an old script that starts with on open theFile:

2012-10-16 16:25:48.293 Quicksilver[41315:752b] Perform AppleScript Action Error: "NSAppleScriptErrorNumber" = -1708;
Owner

pjrobertson commented Oct 25, 2012

Yep, good catch on that one, thanks.
It should be fixed now.

It should probably return the file in its new location (if such a thing is possible), but that's obviously an issue with this particular script.

Yeah you'd just need to do something like (untested)

return (Posix path of THEFILE) as alias
Owner

skurfer commented Oct 30, 2012

OK, the old scripts work now, but the example you gave fails. :-/ I saw this when testing the other day, but wanted to be sure Launch Services forgot about any old versions so I waited a while. It crashes with this:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[QSAppleScriptActions eventDescriptorForIObject:]: unrecognized selector sent to instance 0x106925800'
Owner

skurfer commented Jan 31, 2013

This is pretty close, right? 1.0?

Owner

pjrobertson commented Jan 31, 2013

uuuuh, yes

OK :D

On 31 January 2013 20:18, Rob McBroom notifications@github.com wrote:

This is pretty close, right? 1.0?


Reply to this email directly or view it on GitHubhttps://github.com/quicksilver/Quicksilver/pull/1048#issuecomment-12963386.

Will it include #1264 also?

Owner

pjrobertson commented Jan 31, 2013

We'll see how it goes, but thanks for reminding me.

We're working to a pretty tight schedule over the next few days ;-)

On 31 January 2013 22:52, David Rees notifications@github.com wrote:

Will it include #1264https://github.com/quicksilver/Quicksilver/issues/1264also?


Reply to this email directly or view it on GitHubhttps://github.com/quicksilver/Quicksilver/pull/1048#issuecomment-12970883.

Owner

pjrobertson commented Feb 1, 2013

OK, all outstanding problems should be fixed. I've actually tested it this time :)

... and I just couldn't stay away, once I'd got 'comfortable' with the scripting definitions.

I've added two new handlers which can be used in AppleScripts:

on get direct types and on get indirect types

You use them to specify the valid direct types the action will display for, and the files that appear in the 3rd pane for the action, respectively. An example:

Take either of the 'shorten URL' AppleScripts from http://qsapp.com/wiki/Shorten_URL_(AppleScript) and save them in the Actions folder (~/Lib/App support/QS/Actions)

Restart QS to add the action, and you'll notice that you can find the action for any text that's in the 1st pane. But preferably, you only want the action to display for URL types. Go ahead and add this to the script (on the 2nd line):

using terms from... (1st line. Add the text below:)
    on get direct types
        return {"Apple URL pasteboard type"}
    end get indirect types

Now, the action will only display for URLs. The types are listed here: http://qsapp.com/wiki/AppleScript_Types (messy atm, I'll tidy it up)

(Note to devs: since this then just uses [QSLib arrayForType:type] under the hood, you can specify any valid type so e.g. QSRemoteHostType or whatever)

Owner

pjrobertson commented Feb 1, 2013

@studgeek and @philostein

I've added lots of documentation to the wiki on how to use these new handlers. See
http://qsapp.com/wiki/AppleScript_Types#A_real_live_example
and for an overview of AppleScript actions see http://qsapp.com/wiki/AppleScript_Actions
please update them if you have more info. I'm sure you're both much more experiences with QS AppleScripts than I am!

We would greatly appreciate it if you could both build Quicksilver with these changes and test them out. We're running a tight schedule at the moment (you'll see why soon!) so any second you could spare would be really helpful to us

Owner

pjrobertson commented Feb 1, 2013

Will somebody please stop me before this gets out of hand ;-)

I've now added the option for the 3rd pane to be optional.
In the get argument count handler, just return 3

on get argument count
      return 3
end on get argument count
Owner

pjrobertson commented Feb 1, 2013

Rebased against master.
The last FIRST! commit fixes a strange thing whereby if an action has indirectObject set, but also returned an array in validIndirectsFor.... the 3rd pane would show.
Now, the 3rd pane only shows if you explicitly tab to it. This means that if you:

  • Use an action with indirectOptional (e.g. "some text" ⇥ Create File[...])
  • Tab to the (hidden) 3rd pane and set a folder
  • Tab away from the 3rd pane
  • Note the 3rd pane hides again.

I quite like this though because: a) it fixes the bug mentioned above, b) it makes the 'optional' factor even more obvious, c) cool that QS reveals and hides the pane. Kinda seems to me like 'peeking' round a corner, d) you can still see the iObject selected in the interface's 'description' label (depends on the interface - but works in Nostromo)

For @philostein, @studgeek (and potentially @daniels220) I've built a copy of this app, which you can test if you download it from here
Edit: this build isn't GateKeeper - proof

studgeek commented Feb 1, 2013

I'm not about to stop you, this is awesome :). It opens up a huge range of possibilities for not just AppleScript, but general scripting by wrapping it in AppleScript.

I made a few changes to the wiki, please correct if I made a mistake:

  • Separated "open" handlers and "argument" handlers and added explanation about the difference and when they are called (this is something that confused me when I first started doing QS AppleScripts).
  • Changed the "open" descriptions to say "receive files" rather than "send files".
  • Added syntax highlighting to the table.

Also, a question, open isn't really files anymore, is it? Its really a list of objects, limited to what is returned by get direct/indirect types. And are the items always in string form, or are they AppleScript "objects" in some cases (files)? I've wondered about that for a while (I'm also new to AppleScript).

Also, for AppleScript Types, there may be other types also that are introduced by other plugins, right? Just thinking of adding that to the wiki. Also, is there a way to figure them out that I could document also?

studgeek commented Feb 1, 2013

From @pjrobertson in #947

You can see the what 'handlers' exist in the wiki.
I'll add a section on 'returning' items to Quicksilver. At the moment you can only return strings (which Quicksilver will then inspect and potentially turn into a file/URL/string/email address etc).

So if you return a string quicksilver will parse it as the next direct object? Cool.

I'm also wondering about calling QS from outside an QS AppleScript. I know you can do it using the command line plugin, but is there an AppleScript version as well?

studgeek commented Feb 1, 2013

As I look at the closing of #947, I thought i would point out one other plugin vs AppleScript gap to consider for the future which is adding items to catalog.

For example, you could use a script to add to the catalog specific URLs, including different URLs schemes like youtube, itunes, messages, and custom ones (Apple URL Schemes).

So there would be a handler called "on get catalog type" that would return a type string and "on get catalog items" that would return an array of object strings. Those strings would then be objects that the scripts could indicate they support using "get direct/indirect types".

More generically, I could see cases where you want to introduce a whole new types like "monitor" or "USB Device" so you can write applescripts for that type. So you could actually introduce a new type and a whole set of actions for it with just a little applescript coding. You could also use the new types as indirect items that are appropriate for the script. For example you could add a "monitor" type, then have a "move to monitor" action that takes the indirect monitor name. The script's "on get catalog items" would scan and return the list of monitors.

Just a thought for the future...

Owner

pjrobertson commented Feb 1, 2013

Great, I'm glad it's useful! And thanks for making edits to the wiki. I agree with you on everything you've done. Much clearer :)

I've edited it a little further:

  • Added info on returning items.
  • Added info on on process text. We'd forgotten about that one.

Also, a question, open isn't really files anymore, is it? Its really a list of objects, limited to what is returned by get direct/indirect types

Yes, which makes me realise that on process text is a bit redundant now, but it has its uses, as it means you can easily set up a script that takes text without having to set any argument handlers (and for backwards compat of course)

And are the items always in string form, or are they AppleScript "objects" in some cases (files)?

Strings or files at the moment. Quicksilver will test to see if the objects are files. If they are it'll send file objects to the script, otherwise a 'string representation' of the object. (this can be misleading as it varies from object to object - to see the string representation of an object select it in the 1st pane, close QS, open QS then press '.' to enter text mode)

Also, for AppleScript Types, there may be other types also that are introduced by other plugins, right? Just thinking of adding that to the wiki. Also, is there a way to figure them out that I could document also?

Correct, I'd planned on adding some more to the list, but if you're happy to do so, here's the best way:

  • Download a debug build I've just made from here
  • Enable the QS menu item (prefs → Application → show menu bar item)
  • Select an object in the 1st pane then go to the menu item and choose Debug → Log object to console
  • Go to Console.app and look at the log. You'll see a data part like the following, it contains all the 'types' of the object on the left hand side. The example below shows a log for a Transmit Plugin object. You can see the object has a URL type and a 'QSTransmitSiteType' specific to the plugin.
    data =     {
        "Apple URL pasteboard type" = "sftp://qs:PasswordInKeychain@qsapp.com/home/qs/public_html";
        "QSTransmitSiteType" = "7E78BA8C-8EAD-4D42-85DA-12C7A2654AE3";
    };

So if you return a string quicksilver will parse it as the next direct object? Cool.

Yes :)

I'm also wondering about calling QS from outside an QS AppleScript. I know you can do it using the command line plugin, but is there an AppleScript version as well?

A good idea, I mentioned it in my comment on #947 that it's something to add in the future. Perhaps we should open another 'AppleScript specific' feature request issue.

Just to make sure - are you testing the version of Quicksilver I uploaded, and more importantly... is it working?!

Thanks for your help!

Owner

skurfer commented Feb 1, 2013

Just to make sure - are you testing the version of Quicksilver I uploaded, and more importantly... is it working?!

And even more importantly, does this mean I don't have to test it? ;-)

(I will. Grumble grumble.)

Owner

skurfer commented Feb 2, 2013

Looks good. Old scripts work, and the example you posted to move files works.

I still see the console message from #783 though. That's not going to hold this up, but I thought I'd mention that it's not fixed.

Owner

pjrobertson commented Feb 2, 2013

:(

Still seeing those error messages? What's the script?
I know there are a few logs from +NDCoercion.m:L1619, but I couldn't figure
out how to fix that.
I didn't want to silence the logs because they're external, but it looks
like +NDCoercion will never be updated because Apple improved their own
AppleScript stuff, so maybe we should go ahead and mod it?

On 2 February 2013 01:24, Rob McBroom notifications@github.com wrote:

Looks good. Old scripts work, and the example you posted to move files
works.

I still see the console message from #783https://github.com/quicksilver/Quicksilver/issues/783though. That's not going to hold this up, but I thought I'd mention that
it's not fixed.


Reply to this email directly or view it on GitHubhttps://github.com/quicksilver/Quicksilver/pull/1048#issuecomment-13022348.

Owner

skurfer commented Feb 2, 2013

using terms from application "Quicksilver"
    on process text theText
        set logEntry to the quoted form of theText
        do shell script "/Users/rob/bin/tlog " & logEntry
    end process text
end using terms from

You obviously won't have tlog, but the example I posted on the original issues still generates the error. I don't remember the details, but I seem to have tracked it to QSObject_AEConversion.m. It can wait if you don't want to bother with it.

Contributor

philostein commented Feb 3, 2013

Tried these changes, and I can set the object types for pane 1 and 3, but only if I compile the script so:

on «event DAEDgdob»
    return {"qs.process"}
end «event DAEDgdob»

on «event DAEDgiob»
    return {"NSFilenamesPboardType"}
end «event DAEDgiob»

The on get direct types syntax fails with a Expected function name, command name or function name but found “get”. compile error in ASE.

The on open files dObject with iObject syntax fails with a file dObject is illegal as a formal parameter. error. I don't know the raw code for that one.

I don't have any other QSes on my system now, 'ghost' or otherwise. :)

FYI: AS QS crashes 5 or 6 times on launch, but eventually it stays open and is generally fine until the next relaunch.

Owner

pjrobertson commented Feb 3, 2013

@philostein - thanks for trying this out. The errors you have are most definitely related to the AppleScript editor picking up the wrong QS.

If you go to AppleScript Editor → File → Open Dictionary, how many 'Quicksilvers' are in the list?
If you open one of the dictionaries and got to the 'script handlers' section do you see the new ones I've defined?

Thanks for trying this out - so do the scripts work (when compiled as you say), and any suggestions/problems? :)

You guys are amazing, thank you so much. Looking forward to the final release of these changes.

Contributor

philostein commented Feb 3, 2013

There's only 1 QS in the dictionaries list, and the new handlers are there, but…

relaunching ASE did the trick! Must have a dictionary cache or some such. Annoying.

These changes work great! I was able to define different object types for the scripts to be valid for. They don't appear for other object types. The open files handler script only appears for files.

I'm not sure about the return 3 hidden 3rd pane part. If the user doesn't tab to pane 3, it's not possible to know what iObject is. QS also seems to randomly populate pane 3. Once, the example file mover script tried to move a file to Reminders.app, and another time to an Applescript file.

I'll update some of my scripts to use the object types and open files handlers, and then post back here.

One idea: object types for specific objects such as Sparrow.app or Todo.txt - then custom actions could be dragged to the top of Actions preferences and appear first for only those objects. I realise though that you're extending how QS handles generic object types, so I understand if my idea is impractical. :)

Owner

skurfer commented Feb 4, 2013

So everyone good with this?

studgeek commented Feb 4, 2013

I have been traveling and have not had a chance to test it, but am very excited for it none the less. I can create a separate issue for the "adding to the catalog/types" idea I listed above.

@skurfer skurfer added a commit that referenced this pull request Feb 7, 2013

@skurfer skurfer Merge pull request #1048 from pjrobertson/AppleScript
AppleScript action improvements. Fixes #1023
f5da5b8

@skurfer skurfer merged commit f5da5b8 into quicksilver:master Feb 7, 2013

Owner

skurfer commented Feb 7, 2013

Might need some help with the release notes on this one. All I have for the moment is:

Contributor

philostein commented Feb 10, 2013

I'd like to make a command that goes like this: [email address]>[action]>[file]
But if use the following with on open files _emailAddress with _attachment, QS crashes:

on get direct types
    return {"NSStringPboardType"}
end get direct types

on get indirect types
    return {"NSFilenamesPboardType"}
end get indirect types

This would be useful to get an email address from Contacts as a recipient for an attachment in pane 3.

The other way round works well ([file]>[action]>[typed email address].

Just sent the crash report in QS.

Contributor

philostein commented Feb 10, 2013

Fixed it, used on process text _emailAddress with _attachment instead, and it worked perfectly!

This is really useful. :)

Owner

pjrobertson commented Feb 10, 2013

Glad it's fixed. QS still probably shouldn't crash, can you post the full
AS that was crashing QS?

Ta

On 10 February 2013 12:58, philostein notifications@github.com wrote:

Fixed it, used on process text _emailAddress with _attachment instead,
and it worked perfectly!

This is really useful. :)


Reply to this email directly or view it on GitHubhttps://github.com/quicksilver/Quicksilver/pull/1048#issuecomment-13349386..

Contributor

philostein commented Feb 10, 2013

Sure:

using terms from application "Quicksilver"
on get direct types
    return {"NSStringPboardType"}
end get direct types

on get indirect types
    return {"NSFilenamesPboardType"}
end get indirect types

on open files _emailAddress with _attachment
    try
        -- Put your email address between the following quotes:
        set _myAddress to "johndoe@gmail.com"
        tell me to set _body to (current date) as text

        set _attachmentText to _attachment as text
        set _path to POSIX path of _attachmentText

        tell application "Sparrow"
            set _outgoingMessage to make new outgoing message with properties {subject:_attachmentText, content:_body, sender:_myAddress}

            tell _outgoingMessage to make new to recipient with properties {address:_emailAddress}
            tell _outgoingMessage to make new mail attachment with properties {filename:_path}

            sendmessage _outgoingMessage with to recipient and mail attachment
        end tell

    on error a number b
        activate
        display dialog a with title "Sparrow Attachment"
    end try
end open files

on get argument count
    return 2
end get argument count
end using terms from

@pjrobertson I'm interested in getting the object types again Is there a way to get it in a beta/release build. Failing that, how do I create a debug build? I can follow http://qsapp.com/wiki/Building_Quicksilver, but what else do I need to do to get the object types in the log.

I'll add I agree with #1817 that it would be very handy to just add an action for this (maybe one that is off by default).

Owner

pjrobertson commented Sep 25, 2014

Hmmm... the only way that I know of is to use a debug build. The debug build adds an option in the mneu bar icon called 'log object to console'. That will show all the types that exist for a single object (that's selected in QS' first pane)
Building should be pretty easy if you follow those instructions. I've just updated them for the latest Xcode 6 release

Owner

skurfer commented Sep 25, 2014

I don’t suppose you figured out how to sign the app for Gatekeeper with Xcode 6. 😃 Yes, they changed it again, and I can’t even get it to sign on my wife’s machine with Xcode 5.

Owner

pjrobertson commented Sep 25, 2014

hmm.... nope not really :(
Is xcodebuild broken? You might need to update your certificates? I'm assuming it works if you add the certificate in the 'build settings', but we know that that's no good for git/sharing

Owner

tiennou commented Sep 25, 2014

Actually, I think you can use Developer.xcconfig for that. Bonus points if you can manage to make a nice section :

# Set this env variable to perform signed builds
BUILD_CERTIFICATE_ENV_VAR = 

Commit the file with those change for the posterity, and then make git ignore subsequent changes for this file — I know there's a way to exclude a file while having it still checked out.

Owner

pjrobertson commented Sep 25, 2014

I thought the env variable was
env x='() { :;}; echo vulnerable' bash -c 'echo hello'
;-)

Owner

skurfer commented Sep 25, 2014

The Tools/qsrelease script already takes care of setting up the environment. The problem is much more complicated. Long story short, I found some discussion on-line that led me to blame top-level files in the frameworks. If I do this before signing, it works again:

rm Quicksilver.app/Contents/Frameworks/*.framework/PkgInfo

The app appears to run, so I guess we don’t need those files. Can we change the framework build process so they don’t get created in the first place? I have some documentation open for that, but haven’t had a chance to read it.

FYI, I documented the current instructions for looking up other object types in http://qsapp.com/wiki/AppleScript_Types#Other_Quicksilver_Object_Types (along with basic UTI stuff).

Hey, sweet, exactly what I was looking for! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment