Jump to content

Making script filter results act like keywords


Recommended Posts

I've been working on this for a while, and although I've gotten close, I haven't achieved complete success. My goal is basically to have the workflow script generate the workflow. I'd like to have a single top-level keyword and have the script generate everything else dynamically. This mostly works, but implementing Alfred's "waiting for input" subtitle behavior is proving difficult. The closest I've come up with is having the script filter spawn off a separate process to do the long action and return an item with the "waiting" subtitle. The secondary process will update Alfred when the process is finished via AppleScript.

 

Telling Alfred to perform a new query via Applescript opens a new window, which has two downsides:

  • It causes an annoying flicker when the current window closes and the new one opens
  • If the user closed Alfred, Alfred is going to mysteriously pop open again when the subprocess completes.

Is there a better way to do this, or is there some chance that Alfred might add support for updating the currently open Alfred window via Applescript?

Link to comment

I've been working on this for a while, and although I've gotten close, I haven't achieved complete success. My goal is basically to have the workflow script generate the workflow. I'd like to have a single top-level keyword and have the script generate everything else dynamically. This mostly works, but implementing Alfred's "waiting for input" subtitle behavior is proving difficult. The closest I've come up with is having the script filter spawn off a separate process to do the long action and return an item with the "waiting" subtitle. The secondary process will update Alfred when the process is finished via AppleScript.

 

Telling Alfred to perform a new query via Applescript opens a new window, which has two downsides:

  • It causes an annoying flicker when the current window closes and the new one opens
  • If the user closed Alfred, Alfred is going to mysteriously pop open again when the subprocess completes.

Is there a better way to do this, or is there some chance that Alfred might add support for updating the currently open Alfred window via Applescript?

 

I'm not extremely clear on what you're trying to do here but... going with the idea of having a single keyword to start things off and then recalling a script filter repeatedly... are you using external triggers? This would be a nice way of doing it. I've used this in a few workflows where I have an initial script filter to get me going and then then results will have a value that it passes to an external trigger, that has a script filter following it. So it passes the value of the selected result right back into the script filter. Does that make sense? This may take two script filters though. Mine does.

Link to comment

I'm not extremely clear on what you're trying to do here but... going with the idea of having a single keyword to start things off and then recalling a script filter repeatedly... are you using external triggers? This would be a nice way of doing it. I've used this in a few workflows where I have an initial script filter to get me going and then then results will have a value that it passes to an external trigger, that has a script filter following it. So it passes the value of the selected result right back into the script filter. Does that make sense? This may take two script filters though. Mine does.

 

 

What I would like is for a single script to handle everything  -- when called as a script filter it should handle user interaction, including generating the keywords that are currently applicable. When called as a script action, it should do...actions. In general, my workflows look like this (this one is for interacting with the Toggl time tracking service):

 

Screen%20Shot%202014-09-23%20at%207.40.0

 

The same executable handles both the "tgl" keyword and all the action blocks. In this case, typing the "tgl" keyword presents the user with this:

 

Screen%20Shot%202014-09-23%20at%207.40.1

These entries look and act essentially like normal keywords, but they're generated by the script filter. These are the options a user sees when they've logged in to Toggl with the workflow. If they haven't logged in, they'd only be presented with a single login option. My goal is to present the user with options that make sense based on the state of the workflow. Aside from hiding options that don't make sense at any given time, generating the UI programmatically can let a user configure the UI to some extent, such as hiding (or maybe even adding) options and changing keywords. This configuration information is stored in the workflow's data directory, so that it survives workflow upgrades.

 

My Toggl workflow works by letting the user drill down into their data. For example, listing timers and filtering by a name gives:

 

Screen%20Shot%202014-09-23%20at%207.55.5

Tab completing a particular entry fills in the records ID (masked below) as the placeholder for the item and shows details about the timer, which can be modified.

 

Screen%20Shot%202014-09-23%20at%207.56.0

The main problem that comes up with workflows structured like this happens when one of the actions takes time, like when it's downloading data from toggl. With a normal keyword, Alfred will let the user know that Alfred is busy by showing the "Please Wait" subtext, but that doesn't work for script filter results. Showing my own "Please Wait" text and then using a subprocess and AppleScript works to some extent, but has the issues I outlined in my original post. I've looked a bit at external triggers, but those have the same problems as sending a query via AppleScript with the added issues of losing both the context you get from seeing the full command line and the ability to simply backspace to go to a higher level of context. (At least, that's how they seemed to work when I tried them out.)

 

Some other ways to handle this without resorting to AppleScript and async processes (which I would prefer to avoid) might be to 1) let a script filter specify "please waiting" text for items, or have a workflow-wide "Please wait" fallback, and have Alfred switch the subtitle of the currently displayed item(s) to the "Please wait" text while waiting for the current script invocation to complete; or 2) to have a global "busy" indicator (spinner, text, something) in the Alfred window that shows that Alfred is waiting for a script filter to complete.

Link to comment

What I would like is for a single script to handle everything  -- when called as a script filter it should handle user interaction, including generating the keywords that are currently applicable. When called as a script action, it should do...actions. In general, my workflows look like this (this one is for interacting with the Toggl time tracking service):

 

Screen%20Shot%202014-09-23%20at%207.40.0

 

The same executable handles both the "tgl" keyword and all the action blocks. In this case, typing the "tgl" keyword presents the user with this:

 

Screen%20Shot%202014-09-23%20at%207.40.1

These entries look and act essentially like normal keywords, but they're generated by the script filter. These are the options a user sees when they've logged in to Toggl with the workflow. If they haven't logged in, they'd only be presented with a single login option. My goal is to present the user with options that make sense based on the state of the workflow. Aside from hiding options that don't make sense at any given time, generating the UI programmatically can let a user configure the UI to some extent, such as hiding (or maybe even adding) options and changing keywords. This configuration information is stored in the workflow's data directory, so that it survives workflow upgrades.

 

My Toggl workflow works by letting the user drill down into their data. For example, listing timers and filtering by a name gives:

 

Screen%20Shot%202014-09-23%20at%207.55.5

Tab completing a particular entry fills in the records ID (masked below) as the placeholder for the item and shows details about the timer, which can be modified.

 

Screen%20Shot%202014-09-23%20at%207.56.0

The main problem that comes up with workflows structured like this happens when one of the actions takes time, like when it's downloading data from toggl. With a normal keyword, Alfred will let the user know that Alfred is busy by showing the "Please Wait" subtext, but that doesn't work for script filter results. Showing my own "Please Wait" text and then using a subprocess and AppleScript works to some extent, but has the issues I outlined in my original post. I've looked a bit at external triggers, but those have the same problems as sending a query via AppleScript with the added issues of losing both the context you get from seeing the full command line and the ability to simply backspace to go to a higher level of context. (At least, that's how they seemed to work when I tried them out.)

 

Some other ways to handle this without resorting to AppleScript and async processes (which I would prefer to avoid) might be to 1) let a script filter specify "please waiting" text for items, or have a workflow-wide "Please wait" fallback, and have Alfred switch the subtitle of the currently displayed item(s) to the "Please wait" text while waiting for the current script invocation to complete; or 2) to have a global "busy" indicator (spinner, text, something) in the Alfred window that shows that Alfred is waiting for a script filter to complete.

 

Is there some reason that you have to have a single keyword? It seems like a lot of work to accomplish something that could more than likely be done much easier

Link to comment

I don't really need to have a single keyword, but I think the concept of context-dependent keywords is worth exploring. A service that doesn't work until you login, for example, should ideally not present you with a lot of unusable actions before you've logged in. You can certainly make it work by having those actions inform you that they won't work until you've logged in, and I've done that in the past, but I'd prefer to prevent that situation from arising in the first place (when possible).

 

As for ease of development, I've created a number of workflows, and I've found that implementing most of the functionality in code is generally easier (for me) than trying to structure a workflow using blocks in the workflow editor. If I'm creating a workflow and I decide I'd rather use a different base keyword or prefix, I really hate having to go back and change 20 different blocks. When 90% of the workflow is in code, though, making sweeping changes to its functionality (or just globally updating a keyword) is easy. I don't like UI builders very much, either, so at least I'm consistent. :)

Link to comment
  • 2 weeks later...

Agree 100% wrt keeping stuff in code and the utility of external triggers.

 

If I want data from a webservice/app that will take a second or two to load, I usually go the background process route. But instead of having that process talk to Alfred, I show an extra result item notifying the user that the data is being updated and use cached data instead.

 

Unfortunately, this means the user has to re-run the command to use the latest data, but I think that's better than Alfred randomly being called from the background, especially as the user might be trying to do something else with Alfred at the time.

 

This is how I normally do it.

 

The way I see it, this is a hard limitation with Alfred: the optimal solution just isn't available.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...