awgo: github.com/deanishe/awgo Index | Examples | Files | Directories

package aw

import "github.com/deanishe/awgo"

Package aw is a utility library/framework for building workflows for Alfred. https://www.alfredapp.com/

It provides APIs for interacting with Alfred (e.g. generating Script Filter feedback and setting workflow variables) with a host of convenience functions, plus support for common workflow idioms, such as caching data from applications/web services and updating the cache in a background process to keep your workflow super-responsive.

NOTE: AwGo is currently in development. The API *will* change as I learn to write idiomatic Go, and should not be considered stable until v1.0.

This library is released under the MIT licence, which you can read online at https://opensource.org/licenses/MIT

Read this documentation online at http://godoc.org/github.com/deanishe/awgo

Features

The main features are:

- Easy access to Alfred context, such as data and cache directories.
- Fluent API for generating Alfred JSON feedback for Script Filters.
- Support for all applicable Alfred features up to v3.5.
- Fuzzy sorting/filtering.
- Simple, but powerful, API for caching/saving workflow data.
- Catches panics, logs stack trace and shows user an error message.
- Workflow updates API with built-in support for GitHub releases.
- Pre-configured logging for easier debugging, with a rotated log file.
- "Magic" queries/actions for simplified development and user support.
- macOS system icons.

Usage

Typically, you'd call your program's main entry point via Run(). This way, the library will rescue any panic, log the stack trace and show an error message to the user in Alfred.

program.go:

package main

// Package is called aw
import "github.com/deanishe/awgo"

// Your workflow starts here
func run() {
	// Add a "Script Filter" result
	aw.NewItem("First result!")
	// Send results to Alfred
	aw.SendFeedback()
}

func main() {
	// Wrap your entry point with Run() to catch and log panics and
	// show an error in Alfred instead of silently dying
	aw.Run(run)
}

In the Script Filter's Script box (Language = /bin/bash with input as argv):

./program "$1"

The Item struct isn't intended to be used as the workflow's data model, just as a way to encapsulate search results for Alfred. In particular, its variables are only settable, not gettable. However, the Feedback struct, to which Items belong, supports fuzzy.Interface, so in most situations, it's not necessary to implement fuzzy.Interface yourself in order to use fuzzy filtering.

Most package-level functions call the methods of the same name on the default Workflow struct. If you want to use custom options, you can create a new Workflow with New(), or reconfigure the default Workflow via the package-level Configure() function.

Check out the examples/ subdirectory for some simple, but complete, workflows which you can copy to get started.

Fuzzy filtering

Subpackage fuzzy provides a fuzzy search algorithm modelled on Sublime Text's search. Implement fuzzy.Interface to make a slice fuzzy-sortable.

The Feedback struct implements this interface.

Feedback and Workflow provide an additional Filter() method, which fuzzy-sorts the contained Items and removes any that do not match the query.

See examples/fuzzy for a basic demonstration.

See examples/bookmarks for a demonstration of implementing fuzzy.Interface on your own structs and customising the fuzzy sort settings.

Sending results to Alfred

Generally, you'll want to use NewItem() to create items, then SendFeedback() to generate the JSON and send it to Alfred (i.e. print it to STDOUT).

You can only call a sending method once: multiple calls would result in invalid JSON, as there'd be multiple root objects, so any subsequent calls to sending methods are logged and ignored. Sending methods are:

SendFeedback()
Fatal()
Fatalf()
FatalError()
Warn()
WarnEmpty()  // only sends if there are no items

The Workflow struct (more precisely, its Feedback struct) retains the Item, so you don't need to. Just populate it and then call SendFeedback() when all your results are ready.

There are additional helper methods for specific situations.

NewFileItem() returns an Item pre-populated from a filepath (title, subtitle, icon, arg, etc.).

FatalError(), Fatal() and Fatalf() will immediately send a single result to Alfred with an error message and then call log.Fatalf(), terminating the workflow.

Warn() also immediately sends a single result to Alfred with a warning message (and icon), but does not terminate the workflow. However, because the JSON has already been sent to Alfred, you can't send any more results after calling Warn().

WarnEmpty() calls Warn() if there are no (other) Items to send to Alfred.

If you want to include a warning with other results, use NewWarningItem().

Logging

AwGo uses the default log package. It is automatically configured to log to STDERR (Alfred's debugger) and to a logfile in the workflow's cache directory.

The log file is rotated when it exceeds 1 MiB in size. One previous log is kept.

AwGo detects when Alfred's debugger is open (Workflow.Debug() returns true) and in this case prepends filename:linenumber: to log messages.

Saving and caching data

Alfred provides data and cache directories for each workflow. The data directory is for permanent data and the cache directory for temporary data. You should use the CacheDir() and DataDir() methods to get the paths to these directories, as the methods will ensure that the directories exist.

AwGo's Workflow struct has a simple API for saving data to these directories. There are basic load/store methods for saving bytes or (un)marshalling structs to/from JSON, plus LoadOrStore methods that return cached data if they exist and are new enough, or refresh the cache via a provided function, then return the data.

Workflow.Data points to the workflow's data directory, Workflow.Cache is configured to point to the workflow's cache directory, and Workflow.Session also uses the cache directory, but its cached data expire when the user closes Alfred or runs a different workflow.

See the Cache and Session structs for the API.

Background jobs

AwGo provides a simple API to start/stop background processes via the RunInBackground(), IsRunning() and Kill() functions. This is useful for running checks for updates and other jobs that hit the network or take a significant amount of time to complete, allowing you to keep your Script Filters extremely responsive.

See examples/update for one possible way to use this API.

Performance

For smooth performance in Alfred, a Script Filter should ideally finish in under 0.1 seconds. 0.3 seconds is about the upper limit for your workflow not to feel sluggish.

As a rough guideline, loading and sorting/filtering ~20K is about the limit before performance becomes noticeably hesitant.

If you have a larger dataset, consider using something like sqlite—which can easily handle hundreds of thousands of items—for your datastore.

Index

Examples

Package Files

background.go cache.go context.go doc.go feedback.go icons.go magic.go workflow.go

Constants

const AwGoVersion = "0.13.2"

AwGoVersion is the semantic version number of this library.

const DefaultMagicPrefix = "workflow:"

DefaultMagicPrefix is the default prefix for "magic" arguments. This can be overriden with the MagicPrefix value in Options.

Variables

var (
    DefaultMagicActions = []MagicAction{
        openLogMagic{},
        openCacheMagic{},
        clearCacheMagic{},
        openDataMagic{},
        clearDataMagic{},
        resetMagic{},
    }
)

Magic actions registered by default.

func BundleID Uses

func BundleID() string

BundleID returns the workflow's bundle ID. This library will not work without a bundle ID, which is set in the workflow's main setup sheet in Alfred Preferences.

func CacheDir Uses

func CacheDir() string

CacheDir returns the path to the workflow's cache directory. The directory will be created if it does not already exist.

func CheckForUpdate Uses

func CheckForUpdate() error

CheckForUpdate retrieves and caches the list of available releases.

func ClearCache Uses

func ClearCache() error

ClearCache deletes all files from the workflow's cache directory.

func ClearData Uses

func ClearData() error

ClearData deletes all files from the workflow's cache directory.

func DataDir Uses

func DataDir() string

DataDir returns the path to the workflow's data directory. The directory will be created if it does not already exist.

func Debug Uses

func Debug() bool

Debug returns true if Alfred's debugger is open.

func Dir Uses

func Dir() string

Dir returns the path to the workflow's root directory.

func Fatal Uses

func Fatal(msg string)

Fatal displays an error message in Alfred, then calls log.Fatal(), terminating the workflow.

func FatalError Uses

func FatalError(err error)

FatalError displays an error message in Alfred, then calls log.Fatal(), terminating the workflow.

func Fatalf Uses

func Fatalf(format string, args ...interface{})

Fatalf displays an error message in Alfred, then calls log.Fatal(), terminating the workflow.

func Filter Uses

func Filter(query string) []*fuzzy.Result

Filter fuzzy-sorts feedback Items against query and deletes Items that don't match.

func InstallUpdate Uses

func InstallUpdate() error

InstallUpdate downloads and installs the latest version of the workflow.

func IsEmpty Uses

func IsEmpty() bool

IsEmpty returns true if Workflow contains no items.

func IsRunning Uses

func IsRunning(jobName string) bool

IsRunning returns true if a job with name jobName is currently running.

func Kill Uses

func Kill(jobName string) error

Kill stops a background job.

func LogFile Uses

func LogFile() string

LogFile returns the path to the workflow's log file.

func Name Uses

func Name() string

Name returns the workflow's name as specified in the workflow's main setup sheet in Alfred Preferences.

func NewSessionID Uses

func NewSessionID() string

NewSessionID returns a pseudo-random string based on the current UNIX time in nanoseconds.

func OpenCache Uses

func OpenCache() error

OpenCache opens the workflow's cache directory in the default application (usually Finder).

func OpenData Uses

func OpenData() error

OpenData opens the workflow's data directory in the default application (usually Finder).

func OpenHelp Uses

func OpenHelp() error

func OpenLog Uses

func OpenLog() error

OpenLog opens the workflow's logfile in the default application (usually Console.app).

func Reset Uses

func Reset() error

Reset deletes all workflow data (cache and data directories).

func Run Uses

func Run(fn func())

Run runs your workflow function, catching any errors. If the workflow panics, Run rescues and displays an error message in Alfred.

func RunInBackground Uses

func RunInBackground(jobName string, cmd *exec.Cmd) error

RunInBackground executes cmd in the background. It returns an AlreadyRunning error if a job of the same name is already running.

func SendFeedback Uses

func SendFeedback()

SendFeedback generates and sends the JSON response to Alfred. The JSON is output to STDOUT. At this point, Alfred considers your workflow complete; sending further responses will have no effect.

func SessionID Uses

func SessionID() string

SessionID returns the session ID for this run of the workflow. This is used internally for session-scoped caching.

func SetDefaultWorkflow Uses

func SetDefaultWorkflow(w *Workflow)

SetDefaultWorkflow changes the Workflow object used by the package-level functions.

func SetUpdater Uses

func SetUpdater(u Updater)

SetUpdater sets an updater for the workflow.

func SetVersion Uses

func SetVersion(v string)

SetVersion sets the workflow's version string.

func UpdateAvailable Uses

func UpdateAvailable() bool

UpdateAvailable returns true if a newer version is available to install.

func UpdateCheckDue Uses

func UpdateCheckDue() bool

UpdateCheckDue returns true if an update is available.

func Vars Uses

func Vars() map[string]string

Vars returns the workflow variables set on Workflow.Feedback. See Feedback.Vars() for more information.

func Version Uses

func Version() string

Version returns the workflow's version set in the workflow's configuration sheet in Alfred Preferences.

func WarnEmpty Uses

func WarnEmpty(title, subtitle string)

WarnEmpty adds a warning item to feedback if there are no other items.

type AlreadyRunning Uses

type AlreadyRunning struct {
    Name string
    Pid  int
}

AlreadyRunning is the error returned by RunInBackground if a job with the given name is already running.

func (AlreadyRunning) Error Uses

func (a AlreadyRunning) Error() string

Error implements error interface.

type ArgVars Uses

type ArgVars struct {
    // contains filtered or unexported fields
}

ArgVars lets you set workflow variables from Run Script actions. It emits the arg and variables you set in the format required by Alfred.

Use ArgVars.Send() to pass variables to downstream workflow elements.

Code:

// Set workflow variables from Alfred's Run Script Action
av := NewArgVars()
av.Arg("baz")        // Set output (i.e. next action's {query}) to "baz"
av.Var("foo", "bar") // Set workflow variable "foo" to "bar"
av.Send()

Output:

{"alfredworkflow":{"arg":"baz","variables":{"foo":"bar"}}}

func NewArgVars Uses

func NewArgVars() *ArgVars

NewArgVars returns an initialised ArgVars object.

func (*ArgVars) Arg Uses

func (a *ArgVars) Arg(s string) *ArgVars

Arg sets the arg/query to be passed to the next workflow action.

func (*ArgVars) MarshalJSON Uses

func (a *ArgVars) MarshalJSON() ([]byte, error)

MarshalJSON serialises ArgVars to JSON. You probably don't need to call this: use ArgVars.String() instead.

func (*ArgVars) Send Uses

func (a *ArgVars) Send() error

Send outputs the set arg and variables to Alfred by printing a response to STDOUT.

func (*ArgVars) String Uses

func (a *ArgVars) String() (string, error)

String returns a string representation.

If any variables are set, JSON is returned. Otherwise, a plain string is returned.

func (*ArgVars) Var Uses

func (a *ArgVars) Var(k, v string) *ArgVars

Var sets the value of a workflow variable.

func (*ArgVars) Vars Uses

func (a *ArgVars) Vars() map[string]string

Vars returns ArgVars' variables.

type Cache Uses

type Cache struct {
    Dir string // Directory to save data in
}

Cache implements a simple store/load API, saving data to specified directory.

There are two APIs, one for storing/loading bytes and one for marshalling and storing/loading and unmarshalling JSON.

Each API has basic Store/Load functions plus a LoadOrStore function which loads cached data if these exist and aren't too old, or retrieves new data via the provided function, then caches and returns these.

func NewCache Uses

func NewCache(dir string) *Cache

NewCache creates a new Cache using given directory. Directory dir is created if it doesn't exist. The function will panic if directory can't be created.

func (*Cache) Age Uses

func (c *Cache) Age(name string) (time.Duration, error)

Age returns the age of the data cached at name.

func (*Cache) Exists Uses

func (c *Cache) Exists(name string) bool

Exists returns true if the named cache exists.

func (*Cache) Expired Uses

func (c *Cache) Expired(name string, maxAge time.Duration) bool

Expired returns true if the named cache does not exist or is older than maxAge.

func (*Cache) Load Uses

func (c *Cache) Load(name string) ([]byte, error)

Load reads data saved under given name.

func (*Cache) LoadJSON Uses

func (c *Cache) LoadJSON(name string, v interface{}) error

LoadJSON unmarshals a cache into v.

func (*Cache) LoadOrStore Uses

func (c *Cache) LoadOrStore(name string, maxAge time.Duration, reload func() ([]byte, error)) ([]byte, error)

LoadOrStore loads data from cache if they exist and are newer than maxAge. If data do not exist or are older than maxAge, reload is called, and the returned data are cached & returned.

If maxAge is 0, any cached data are always returned.

func (*Cache) LoadOrStoreJSON Uses

func (c *Cache) LoadOrStoreJSON(name string, maxAge time.Duration, reload func() (interface{}, error), v interface{}) error

LoadOrStoreJSON loads JSON-serialised data from cache if they exist and are newer than maxAge. If the data do not exist or are older than maxAge, reload is called, and the returned data are marshalled to JSON and cached, and unmarshalled into v.

If maxAge is 0, any cached data are loaded regardless of age.

func (*Cache) Store Uses

func (c *Cache) Store(name string, data []byte) error

Store saves data under the given name. If data is nil, the file is deleted.

func (*Cache) StoreJSON Uses

func (c *Cache) StoreJSON(name string, v interface{}) error

StoreJSON serialises v to JSON and saves it to the cache. If v is nil, the cache is deleted.

type Context Uses

type Context struct {
    // Version of workflow (from workflow configuration sheet)
    WorkflowVersion string
    // Name of workflow (from configuration sheet)
    Name string
    // Bundle ID (from configuration sheet)
    BundleID string
    // UID assigned to workflow by Alfred
    UID string
    // true if Alfred's debugger is open
    Debug bool
    // Alfred's version string
    AlfredVersion string
    // Alfred's build
    AlfredBuild string
    // ID of user's selected theme
    Theme string
    // Theme's background colour in rgba format, e.g. "rgba(255,255,255,1.0)"
    ThemeBackground string
    // Theme's selection background colour in rgba format
    ThemeSelectionBackground string
    // Path to "Alfred.alfredpreferences" file
    Preferences string
    // Machine-specific hash. Machine preferences are stored in
    // Alfred.alfredpreferences/local/<hash>
    Localhash string
    // Path to workflow's cache directory. Use Workflow.CacheDir() instead
    CacheDir string
    // Path to workflow's data directory. Use Workflow.DataDir() instead
    DataDir string
}

Context contains Alfred and workflow settings extracted from environment variables set by Alfred.

func NewContext Uses

func NewContext() *Context

NewContext creates a new Context initialised from Alfred's environment variables.

type Feedback Uses

type Feedback struct {
    Items  []*Item // The results to be sent to Alfred.
    NoUIDs bool    // If true, suppress Item UIDs.
    // contains filtered or unexported fields
}

Feedback contains Items. This is the top-level object for generating Alfred JSON (i.e. serialise this and send it to Alfred).

Use NewFeedback() to create new (initialised) Feedback structs.

It is important to use the constructor functions for Feedback, Item and Modifier structs.

func NewFeedback Uses

func NewFeedback() *Feedback

NewFeedback creates a new, initialised Feedback struct.

func (*Feedback) Clear Uses

func (fb *Feedback) Clear()

Clear removes any items.

func (*Feedback) Filter Uses

func (fb *Feedback) Filter(query string, opts ...fuzzy.Option) []*fuzzy.Result

Filter fuzzy-sorts feedback Items against query and deletes Items that don't match.

func (*Feedback) IsEmpty Uses

func (fb *Feedback) IsEmpty() bool

IsEmpty returns true if Feedback contains no items.

func (*Feedback) Len Uses

func (fb *Feedback) Len() int

Len implements sort.Interface.

func (*Feedback) Less Uses

func (fb *Feedback) Less(i, j int) bool

Less implements sort.Interface.

func (*Feedback) MarshalJSON Uses

func (fb *Feedback) MarshalJSON() ([]byte, error)

MarshalJSON serializes Feedback to Alfred 3's JSON format. You shouldn't need to call this: use Send() instead.

func (*Feedback) NewFileItem Uses

func (fb *Feedback) NewFileItem(path string) *Item

NewFileItem adds and returns a pointer to a new item pre-populated from path. Title and Autocomplete are the base name of the file; Subtitle is the path to the file (using "~" for $HOME); Valid is true; UID and Arg are set to path; Type is "file"; and Icon is the icon of the file at path.

func (*Feedback) NewItem Uses

func (fb *Feedback) NewItem(title string) *Item

NewItem adds a new Item and returns a pointer to it.

The Item inherits any workflow variables set on the Feedback parent at time of creation.

func (*Feedback) Rerun Uses

func (fb *Feedback) Rerun(secs float64) *Feedback

Rerun tells Alfred to re-run the Script Filter after `secs` seconds.

func (*Feedback) Send Uses

func (fb *Feedback) Send() error

Send generates JSON from this struct and sends it to Alfred (by writing the JSON to STDOUT).

func (*Feedback) Sort Uses

func (fb *Feedback) Sort(query string, opts ...fuzzy.Option) []*fuzzy.Result

Sort sorts Items against query. Uses a fuzzy.Sorter with the specified options.

func (*Feedback) SortKey Uses

func (fb *Feedback) SortKey(i int) string

SortKey implements fuzzy.Interface.

Returns the match field for Item i. If Item's match is unset, returns Item's title instead.

func (*Feedback) Swap Uses

func (fb *Feedback) Swap(i, j int)

Swap implements sort.Interface.

func (*Feedback) Var Uses

func (fb *Feedback) Var(k, v string) *Feedback

Var sets an Alfred variable for subsequent workflow elements.

func (*Feedback) Vars Uses

func (fb *Feedback) Vars() map[string]string

Vars returns the Feedback's workflow variables.

type Icon Uses

type Icon struct {
    Value string   `json:"path"`           // Path or UTI
    Type  IconType `json:"type,omitempty"` // "fileicon", "filetype" or ""
}

Icon represents the icon for an Item.

Alfred supports PNG or ICNS files, UTIs (e.g. "public.folder") or can use the icon of a specific file (e.g. "/Applications/Safari.app" to use Safari's icon.

Type = "" (the default) will treat Value as the path to a PNG or ICNS file.

Type = IconTypeFileIcon will treat Value as the path to a file or directory and use that file's icon, e.g:

icon := Icon{"/Applications/Mail.app", IconTypeFileIcon}

will display Mail.app's icon.

Type = IconTypeFileType will treat Value as a UTI, such as "public.movie" or "com.microsoft.word.doc". UTIs are useful when you don't have a local path to point to.

You can find out the UTI of a filetype by dragging one of the files to a File Filter's File Types list in Alfred, or in a shell with:

mdls -name kMDItemContentType -raw /path/to/the/file

This will only work on Spotlight-indexed files.

var (
    IconWorkflow  *Icon // icon.png (workflow's own icon)
    IconAccount   *Icon // Accounts.icns
    IconBurn      *Icon // BurningIcon.icns
    IconClock     *Icon // Clock.icns
    IconColor     *Icon // ProfileBackgroundColor.icns
    IconColour    *Icon // ProfileBackgroundColor.icns
    IconEject     *Icon // EjectMediaIcon.icns
    IconError     *Icon // AlertStopIcon.icns
    IconFavorite  *Icon // ToolbarFavoritesIcon.icns
    IconFavourite *Icon // ToolbarFavoritesIcon.icns
    IconGroup     *Icon // GroupIcon.icns
    IconHelp      *Icon // HelpIcon.icns
    IconHome      *Icon // HomeFolderIcon.icns
    IconInfo      *Icon // ToolbarInfo.icns
    IconNetwork   *Icon // GenericNetworkIcon.icns
    IconNote      *Icon // AlertNoteIcon.icns
    IconSettings  *Icon // ToolbarAdvanced.icns
    IconSwirl     *Icon // ErasingIcon.icns
    IconSwitch    *Icon // General.icns
    IconSync      *Icon // Sync.icns
    IconTrash     *Icon // TrashIcon.icns
    IconUser      *Icon // UserIcon.icns
    IconWarning   *Icon // AlertCautionIcon.icns
    IconWeb       *Icon // BookmarkIcon.icns
)

Ready-to-use icons based on built-in OS X system icons. These icons are all found in

/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources

The icons are the same as found in the Alfred-Workflow library for Python. Preview them here: http://www.deanishe.net/alfred-workflow/user-manual/icons.html#list-of-icons

type IconType Uses

type IconType string

IconType specifies the type of an aw.Icon struct. It can be an image file, the icon of a file, e.g. an application's icon, or the icon for a UTI.

const (
    // Indicates that Icon.Value is the path to an image file that should
    // be used as the Item's icon.
    IconTypeImageFile IconType = ""
    // Icon.Value points to an object whose icon should be show in Alfred,
    //e.g. combine with "/Applications/Safari.app" to show Safari's icon.
    IconTypeFileIcon IconType = "fileicon"
    // Indicates that Icon.Value is a UTI, e.g. "public.folder",
    // which will give you the icon for a folder.
    IconTypeFileType IconType = "filetype"
)

Valid icon types.

type Item Uses

type Item struct {
    // contains filtered or unexported fields
}

Item is a single Alfred result. Add them to a Feedback struct to generate valid Alfred JSON.

func NewFileItem Uses

func NewFileItem(path string) *Item

NewFileItem adds and returns a new feedback Item pre-populated from path. See Feedback.NewFileItem() for more information.

func NewItem Uses

func NewItem(title string) *Item

NewItem adds and returns a new feedback Item. See Feedback.NewItem() for more information.

The normal way to create a new Item, but not the normal way to use it.

Typically, when you're done adding Items, you call SendFeedback() to send the results to Alfred.

Code:

// Create a new item via the default Workflow object, which will
// track the Item and send it to Alfred when you call SendFeedback()
//
// Title is the only required value.
it := NewItem("First Result").
    Subtitle("Some details here")

// Just to see what it looks like...
data, _ := json.Marshal(it)
fmt.Println(string(data))

Output:

{"title":"First Result","subtitle":"Some details here","valid":false}

func NewWarningItem Uses

func NewWarningItem(title, subtitle string) *Item

NewWarningItem adds and returns a new Feedback Item with the system warning icon (exclamation mark on yellow triangle).

func (*Item) Arg Uses

func (it *Item) Arg(s string) *Item

Arg sets Item's arg, i.e. the value that is passed as {query} to the next action in the workflow.

func (*Item) Autocomplete Uses

func (it *Item) Autocomplete(s string) *Item

Autocomplete sets what Alfred's query will expand to when the user TABs it (or hits RETURN on a result where valid is false)

func (*Item) Copytext Uses

func (it *Item) Copytext(s string) *Item

Copytext is what CMD+C should copy instead of Arg (the default).

func (*Item) Icon Uses

func (it *Item) Icon(icon *Icon) *Item

Icon sets the icon for the Item. Can point to an image file, a filepath of a file whose icon should be used, or a UTI. See the documentation for Icon for more details.

func (*Item) IsFile Uses

func (it *Item) IsFile(b bool) *Item

IsFile tells Alfred that this Item is a file, i.e. Arg is a path and Alfred's File Actions should be made available.

func (*Item) Largetype Uses

func (it *Item) Largetype(s string) *Item

Largetype is what is shown in Alfred's Large Text window on CMD+L instead of Arg (the default).

func (*Item) MarshalJSON Uses

func (it *Item) MarshalJSON() ([]byte, error)

MarshalJSON serializes Item to Alfred 3's JSON format. You shouldn't need to call this directly: use Feedback.Send() instead.

func (*Item) Match Uses

func (it *Item) Match(s string) *Item

Match sets Item's match field. If present, this field is preferred over the item's title for fuzzy sorting via Feedback, and by Alfred's "Alfred filters results" feature.

func (*Item) NewModifier Uses

func (it *Item) NewModifier(key ModKey) *Modifier

NewModifier returns an initialised Modifier bound to this Item. It also populates the Modifier with any workflow variables set in the Item.

func (*Item) Quicklook Uses

func (it *Item) Quicklook(s string) *Item

Quicklook is a path or URL shown in a macOS Quicklook window on SHIFT or CMD+Y.

func (*Item) SetModifier Uses

func (it *Item) SetModifier(m *Modifier) error

SetModifier sets a Modifier for a modifier key.

func (*Item) Subtitle Uses

func (it *Item) Subtitle(s string) *Item

Subtitle sets the subtitle of the item in Alfred's results

func (*Item) Title Uses

func (it *Item) Title(s string) *Item

Title sets the title of the item in Alfred's results

func (*Item) UID Uses

func (it *Item) UID(s string) *Item

UID sets Item's unique ID, which is used by Alfred to remember your choices. Use a blank string to force results to appear in the order you add them.

func (*Item) Valid Uses

func (it *Item) Valid(b bool) *Item

Valid tells Alfred whether the result is "actionable", i.e. ENTER will pass Arg to subsequent action.

func (*Item) Var Uses

func (it *Item) Var(k, v string) *Item

Var sets an Alfred variable for subsequent workflow elements.

func (*Item) Vars Uses

func (it *Item) Vars() map[string]string

Vars returns the Item's workflow variables.

type MagicAction Uses

type MagicAction interface {
    // Keyword is what the user must enter to run the action after
    // AwGo has recognised the magic prefix. So if the prefix is "workflow:"
    // (the default), a user must enter the query "workflow:<keyword>" to
    // execute this action.
    Keyword() string
    // Description is shown when a user has entered "magic" mode, but
    // the query does not yet match a keyword.
    Description() string
    // RunText is sent to Alfred and written to the log file & debugger when
    // the action is run.
    RunText() string
    // Run is called when the Magic Action is triggered.
    Run() error
}

MagicAction is a command that is called directly by AwGo (i.e. your workflow code is not run) if its keyword is passed in a user query. Magic Actions are mainly aimed at making debugging and supporting users easier (via the built-in actions), but it also provides a simple way to integrate your own commands that don't need a "real" UI (via Item.Autocomplete("<prefix>:XYZ") + Item.Valid(false)).

The "update" sub-package registers a Magic Action to check for and install an update, for example.

The built-in Magic Actions provide useful functions for debugging problems with workflows, so you, the developer, don't have to implement them yourself and don't have to hand-hold users through the process of digging out files buried somewhere deep in ~/Library. For example, you can simply request that a user enter "workflow:log" to open the log file or "workflow:delcache" to delete any cached data, instead of asking them to root around somewhere in ~/Library.

To use Magic Actions, it's imperative that your workflow retrieves command-line arguments via Args()/Workflow.Args() instead of accessing os.Args directly (or at least calls Args()/Workflow.Args()).

These functions return os.Args[1:], but first check if any argument starts with the "magic" prefix ("workflow:" by default).

If so, AwGo will take control of the workflow (i.e. your code will no longer be run) and run its own "magic" mode. In this mode, it checks if the rest of the user query matches the keyword for a registered MagicAction, and if so, it runs that action, displaying RunText() in Alfred (if it's a Script Filter) and the log file & debugger.

If no keyword matches, AwGo sends a list of available magic actions to Alfred, filtered by the user's query. Hitting TAB or RETURN on an item will run it.

The built-in magic actions are:

Keyword           | Action
--------------------------------------------------------------------------------------
<prefix>log       | Open workflow's log file in the default app (usually Console).
<prefix>data      | Open workflow's data directory in the default app (usually Finder).
<prefix>cache     | Open workflow's data directory in the default app (usually Finder).
<prefix>deldata   | Delete everything in the workflow's data directory.
<prefix>delcache  | Delete everything in the workflow's cache directory.
<prefix>reset     | Delete everything in the workflow's data and cache directories.
<prefix>help      | Open help URL in default browser.
                  | Only registered if you have set a HelpURL.
<prefix>update    | Check for updates and install a newer version of the workflow
                  | if available.
                  | Only registered if you have set an Updater.

type MagicActions Uses

type MagicActions map[string]MagicAction

MagicActions contains the registered magic actions. See the MagicAction interface for full documentation.

func (MagicActions) Args Uses

func (ma MagicActions) Args(args []string, prefix string) []string

Args runs a magic action or returns command-line arguments. It parses args for magic actions. If it finds one, it takes control of your workflow and runs the action.

If not magic actions are found, it returns args.

func (MagicActions) Register Uses

func (ma MagicActions) Register(actions ...MagicAction)

Register adds a MagicAction to the mapping. Previous entries are overwritten.

func (MagicActions) Unregister Uses

func (ma MagicActions) Unregister(actions ...MagicAction)

Unregister removes a MagicAction from the mapping (based on its keyword).

type ModKey Uses

type ModKey string

ModKey is a modifier key pressed by the user to run an alternate item action in Alfred (in combination with ↩).

It is passed to Item.NewModifier(). ModKeys cannot be combined: Alfred only permits one modifier at a time.

const (
    ModCmd   ModKey = "cmd"   // Alternate action for ⌘↩
    ModAlt   ModKey = "alt"   // Alternate action for ⌥↩
    ModCtrl  ModKey = "ctrl"  // Alternate action for ^↩
    ModShift ModKey = "shift" // Alternate action for ⇧↩
    ModFn    ModKey = "fn"    // Alternate action for fn↩
)

Valid modifier keys

type Modifier Uses

type Modifier struct {
    // The modifier key. May be any of ValidModifiers.
    Key ModKey
    // contains filtered or unexported fields
}

Modifier encapsulates alterations to Item when a modifier key is held when the user actions the item.

Create new Modifiers via Item.NewModifier(). This binds the Modifier to the Item, initializes Modifier's map and inherits Item's workflow variables. Variables are inherited at creation time, so any Item variables you set after creating the Modifier are not inherited.

func (*Modifier) Arg Uses

func (m *Modifier) Arg(s string) *Modifier

Arg sets the arg for the Modifier.

func (*Modifier) Icon Uses

func (m *Modifier) Icon(i *Icon) *Modifier

Icon sets an icon for the Modifier.

func (*Modifier) MarshalJSON Uses

func (m *Modifier) MarshalJSON() ([]byte, error)

MarshalJSON implements the JSON serialization interface.

func (*Modifier) Subtitle Uses

func (m *Modifier) Subtitle(s string) *Modifier

Subtitle sets the subtitle for the Modifier.

func (*Modifier) Valid Uses

func (m *Modifier) Valid(v bool) *Modifier

Valid sets the valid status for the Modifier.

func (*Modifier) Var Uses

func (m *Modifier) Var(k, v string) *Modifier

Var sets a variable for the Modifier.

func (*Modifier) Vars Uses

func (m *Modifier) Vars() map[string]string

Vars returns all Modifier variables.

type Option Uses

type Option func(wf *Workflow) Option

Option is a configuration option for Workflow. Pass one or more Options to New() or Workflow.Configure(). An Option returns its inverse (i.e. an Option that restores the previous value).

Temporarily change Workflow's behaviour then revert it.

Code:

wf := New()
// Default settings (false and 0)
fmt.Println(wf.TextErrors)
fmt.Println(wf.MaxResults)
// Turn text errors on, set max results and save Option to revert
// to previous configuration
previous := wf.Configure(TextErrors(true), MaxResults(200))
fmt.Println(wf.TextErrors)
fmt.Println(wf.MaxResults)
// Revert to previous configuration
wf.Configure(previous)
fmt.Println(wf.TextErrors)
fmt.Println(wf.MaxResults)

Output:

false
0
true
200
false
0

func AddMagic Uses

func AddMagic(actions ...MagicAction) Option

AddMagic registers magic actions with the Workflow.

func Configure Uses

func Configure(opts ...Option) (previous Option)

Configure applies one or more Options to Workflow. The returned Option reverts all Options passed to Configure.

func HelpURL Uses

func HelpURL(URL string) Option

HelpURL sets the link to your issues/page forum thread where users can ask for help. It is shown in the debugger/log if an error occurs ("Get help at http://…").

func LogPrefix Uses

func LogPrefix(prefix string) Option

LogPrefix is the character printed to the debugger at the start of each run. Its purpose is to ensure that the first real log message is shown on its own line. It is only sent to Alfred's debugger, not the log file.

Default: Purple Heart (\U0001F49C)

func MagicPrefix Uses

func MagicPrefix(prefix string) Option

MagicPrefix sets the prefix for "magic" commands. If a user enters this prefix, AwGo takes control of the workflow and shows a list of matching magic commands to the user.

Default: workflow:

func MaxLogSize Uses

func MaxLogSize(bytes int) Option

MaxLogSize sets the size (in bytes) at which the workflow log is rotated. Default: 1 MiB

func MaxResults Uses

func MaxResults(num int) Option

MaxResults is the maximum number of results to send to Alfred. 0 means send all results. Default: 0

func RemoveMagic Uses

func RemoveMagic(actions ...MagicAction) Option

RemoveMagic unregisters magic actions with Workflow.

func SortOptions Uses

func SortOptions(opts ...fuzzy.Option) Option

SortOptions sets the fuzzy sorting options for Workflow.Filter().

func SuppressUIDs Uses

func SuppressUIDs(on bool) Option

SuppressUIDs prevents UIDs from being set on feedback Items. This turns off Alfred's knowledge, so items will be shown in the order you add them. Useful if you need a particular item to be the top result, e.g. a notification of an update.

This setting only applies to Items created *after* it has been set.

func TextErrors Uses

func TextErrors(on bool) Option

TextErrors tells Workflow to print errors as text, not JSON. Set to true if output goes to a Notification.

func Update Uses

func Update(updater Updater) Option

Update sets the updater for the Workflow.

type Session Uses

type Session struct {
    SessionID string
    // contains filtered or unexported fields
}

Session is a Cache that is tied to the `sessionID` value passed to NewSession().

All cached data are stored under the sessionID. NewSessionID() creates a pseudo-random string based on the current UNIX time (in nanoseconds). The Workflow struct persists this value as a session ID as long as the user is using the current workflow via the `AW_SESSION_ID` top-level workflow variable.

As soon as Alfred closes or the user calls another workflow, this variable is lost and the data are "hidden". Session.Clear(false) must be called to actually remove the data from the cache directory, which Workflow.Run() does.

In contrast to the Cache API, Session methods lack an explicit `maxAge` parameter. It is always `0`, i.e. cached data are always loaded regardless of age as long as the session is valid.

TODO: Embed Cache rather than wrapping it.

func NewSession Uses

func NewSession(dir, sessionID string) *Session

NewSession creates and initialises a Session.

func (*Session) Clear Uses

func (s *Session) Clear(current bool) error

Clear removes session-scoped cache data. If current is true, it also removes data cached for the current session.

func (*Session) Exists Uses

func (s *Session) Exists(name string) bool

Exists returns true if the named cache exists.

func (*Session) Load Uses

func (s *Session) Load(name string) ([]byte, error)

Load reads data saved under given name.

func (*Session) LoadJSON Uses

func (s *Session) LoadJSON(name string, v interface{}) error

LoadJSON unmarshals a cache into v.

func (*Session) LoadOrStore Uses

func (s *Session) LoadOrStore(name string, reload func() ([]byte, error)) ([]byte, error)

LoadOrStore loads data from cache if they exist. If data do not exist, reload is called, and the resulting data are cached & returned.

If maxAge is 0, any cached data are always returned.

func (*Session) LoadOrStoreJSON Uses

func (s *Session) LoadOrStoreJSON(name string, reload func() (interface{}, error), v interface{}) error

LoadOrStoreJSON loads JSON-serialised data from cache if they exist. If the data do not exist, reload is called, and the resulting interface{} is cached and returned.

func (*Session) Store Uses

func (s *Session) Store(name string, data []byte) error

Store saves data under the given name. If len(data) is 0, the file is deleted.

func (*Session) StoreJSON Uses

func (s *Session) StoreJSON(name string, v interface{}) error

StoreJSON serialises v to JSON and saves it to the cache. If v is nil, the cache is deleted.

type Updater Uses

type Updater interface {
    UpdateInterval(time.Duration) // Set interval between checks
    UpdateAvailable() bool        // Return true if a newer version is available
    CheckDue() bool               // Return true if a check for a newer version is due
    CheckForUpdate() error        // Retrieve available releases, e.g. from a URL
    Install() error               // Install the latest version
}

Updater can check for and download & install newer versions of the workflow. There is a concrete implementation and documentation in subpackage "update".

type Workflow Uses

type Workflow struct {
    sync.WaitGroup
    // The response that will be sent to Alfred. Workflow provides
    // convenience wrapper methods, so you don't normally have to
    // interact with this directly.
    Feedback *Feedback

    // Workflow execution environment. Contains Alfred and workflow parameters
    // extracted from the environment variables exported by Alfred.
    // See Context for documentation.
    Ctx *Context

    // HelpURL is a link to your issues page/forum thread where users can
    // report bugs. It is shown in the debugger if the workflow crashes.
    HelpURL string

    // LogPrefix is the character printed to the log at the start of each run.
    // Its purpose is to ensure the first real log message starts on its own line,
    // instead of sharing a line with Alfred's blurb in the debugger. This is only
    // printed to STDERR (i.e. Alfred's debugger), not written to the log file.
    // Default: Purple Heart (\U0001F49C)
    LogPrefix string

    // MaxLogSize is the size (in bytes) at which the workflow log is rotated.
    // Default: 1 MiB
    MaxLogSize int

    // MaxResults is the maximum number of results to send to Alfred.
    // 0 means send all results.
    // Default: 0
    MaxResults int

    // SortOptions are options for fuzzy sorting.
    SortOptions []fuzzy.Option

    // TextErrors tells Workflow to print errors as text, not JSON
    // Set to true if output goes to a Notification.
    TextErrors bool

    // Cache is a Cache pointing to the workflow's cache directory.
    Cache *Cache
    // Data is a Cache pointing to the workflow's data directory.
    Data *Cache
    // Session is a cache that stores session-scoped data. These data
    // persist until the user closes Alfred or runs a different workflow.
    Session *Session

    // Updater fetches updates for the workflow.
    Updater Updater

    // MagicActions contains the magic actions registered for this workflow.
    // It is set to DefaultMagicActions by default.
    MagicActions MagicActions
    // contains filtered or unexported fields
}

Workflow provides a simple, consolidated API for building Script Filters and talking to Alfred.

As a rule, you should create a Workflow in main() and call your main entry-point via Workflow.Run(). Use Workflow.NewItem() to create new feedback Items and Workflow.SendFeedback() to send the results to Alfred.

If you don't need to customise Workflow's behaviour in any way, you can use the package-level functions, which call the corresponding methods on the default Workflow object.

See the examples/ subdirectory for some full examples of workflows.

func DefaultWorkflow Uses

func DefaultWorkflow() *Workflow

DefaultWorkflow returns the Workflow object used by the package-level functions.

func New Uses

func New(opts ...Option) *Workflow

New creates and initialises a new Workflow, passing any Options to Workflow.Configure().

For available options, see the documentation for the Option type and the following functions.

New initialises a Workflow with the default settings. Name, bundle ID, version etc. are read from the environment variables set by Alfred.

Code:

wf := New()
// BundleID is read from environment or info.plist
fmt.Println(wf.BundleID())
// Version is from info.plist
fmt.Println(wf.Version())

Output:

net.deanishe.awgo
0.13

Pass one or more Options to New() to configure the created Workflow.

Code:

wf := New(HelpURL("http://www.example.com"), MaxResults(200))
fmt.Println(wf.HelpURL)
fmt.Println(wf.MaxResults)

Output:

http://www.example.com
200

func Rerun Uses

func Rerun(secs float64) *Workflow

Rerun tells Alfred to re-run the Script Filter after `secs` seconds.

func Var Uses

func Var(k, v string) *Workflow

Var sets the value of workflow variable k on Workflow.Feedback to v. See Feedback.Var() for more information.

func Warn Uses

func Warn(title, subtitle string) *Workflow

Warn displays a warning message in Alfred immediately. Unlike FatalError()/Fatal(), this does not terminate the workflow, but you can't send any more results to Alfred.

func (*Workflow) Args Uses

func (wf *Workflow) Args() []string

Args returns command-line arguments passed to the program. It intercepts "magic args" and runs the corresponding actions, terminating the workflow. See MagicAction for full documentation.

func (*Workflow) BundleID Uses

func (wf *Workflow) BundleID() string

func (*Workflow) CacheDir Uses

func (wf *Workflow) CacheDir() string

func (*Workflow) CheckForUpdate Uses

func (wf *Workflow) CheckForUpdate() error

func (*Workflow) ClearCache Uses

func (wf *Workflow) ClearCache() error

func (*Workflow) ClearData Uses

func (wf *Workflow) ClearData() error

func (*Workflow) Configure Uses

func (wf *Workflow) Configure(opts ...Option) (previous Option)

func (*Workflow) DataDir Uses

func (wf *Workflow) DataDir() string

func (*Workflow) Debug Uses

func (wf *Workflow) Debug() bool

func (*Workflow) Dir Uses

func (wf *Workflow) Dir() string

func (*Workflow) Fatal Uses

func (wf *Workflow) Fatal(msg string)

func (*Workflow) FatalError Uses

func (wf *Workflow) FatalError(err error)

func (*Workflow) Fatalf Uses

func (wf *Workflow) Fatalf(format string, args ...interface{})

func (*Workflow) Filter Uses

func (wf *Workflow) Filter(query string) []*fuzzy.Result

func (*Workflow) InstallUpdate Uses

func (wf *Workflow) InstallUpdate() error

func (*Workflow) IsEmpty Uses

func (wf *Workflow) IsEmpty() bool

func (*Workflow) LogFile Uses

func (wf *Workflow) LogFile() string

func (*Workflow) Name Uses

func (wf *Workflow) Name() string

func (*Workflow) NewFileItem Uses

func (wf *Workflow) NewFileItem(path string) *Item

func (*Workflow) NewItem Uses

func (wf *Workflow) NewItem(title string) *Item

func (*Workflow) NewWarningItem Uses

func (wf *Workflow) NewWarningItem(title, subtitle string) *Item

func (*Workflow) OpenCache Uses

func (wf *Workflow) OpenCache() error

func (*Workflow) OpenData Uses

func (wf *Workflow) OpenData() error

func (*Workflow) OpenHelp Uses

func (wf *Workflow) OpenHelp() error

func (*Workflow) OpenLog Uses

func (wf *Workflow) OpenLog() error

func (*Workflow) Rerun Uses

func (wf *Workflow) Rerun(secs float64) *Workflow

func (*Workflow) Reset Uses

func (wf *Workflow) Reset() error

func (*Workflow) Run Uses

func (wf *Workflow) Run(fn func())

func (*Workflow) SendFeedback Uses

func (wf *Workflow) SendFeedback() *Workflow

func (*Workflow) SessionID Uses

func (wf *Workflow) SessionID() string

func (*Workflow) SetUpdater Uses

func (wf *Workflow) SetUpdater(u Updater)

func (*Workflow) SetVersion Uses

func (wf *Workflow) SetVersion(v string)

func (*Workflow) UpdateAvailable Uses

func (wf *Workflow) UpdateAvailable() bool

func (*Workflow) UpdateCheckDue Uses

func (wf *Workflow) UpdateCheckDue() bool

func (*Workflow) Var Uses

func (wf *Workflow) Var(k, v string) *Workflow

func (*Workflow) Vars Uses

func (wf *Workflow) Vars() map[string]string

func (*Workflow) Version Uses

func (wf *Workflow) Version() string

func (*Workflow) Warn Uses

func (wf *Workflow) Warn(title, subtitle string) *Workflow

func (*Workflow) WarnEmpty Uses

func (wf *Workflow) WarnEmpty(title, subtitle string)

Directories

PathSynopsis
examplesPackage examples contains trivial, but complete, Alfred workflows demonstrating features of AwGo and/or useful workflow idioms.
examples/bookmarksWorkflow bookmarks demonstrates implementing fuzzy.Interface on your own structs.
examples/fuzzyWorkflow fuzzy demonstrates AwGo's fuzzy filtering.
examples/updateWorkflow update is an example of how to use AwGo's update API.
examples/workflowsWorkflow workflows searches GitHub repos tagged with "alfred-workflow".
fuzzyPackage fuzzy implements fuzzy sorting and filtering.
updatePackage update implements an API for fetching updates to workflows from remote servers.
utilPackage util contains general helper functions for workflow (library) authors.

Package aw imports 18 packages (graph) and is imported by 20 packages. Updated 2017-12-01. Refresh now. Tools for package owners.