Technical “How-To’s”

Using Alfred to Quickly Open Workspaces

Nico Stewart
Nico Stewart
Share:

Background

I use VS Code for almost all of my development. It allows me to save folders and their custom settings to workspace files.

Alfred is a macOS program serving as a launcher, clipboard manager, finder, and more. In this case, I want to use Alfred to quickly and interactively choose a VS Code workspace to be open.

Required Structure

Alfred’s Script Filters allow us to search a dynamic list for some item and then do something with that item. The documentation then links to the Script Filter JSON format. We will create a script (binary) that outputs all discovered workspaces in the required format.

Code

We can use basic commands to discover all workspaces we want to include:

json
1find ~/code -type file -maxdepth 1 -name '*.code-workspace'

This gives us all workspace files in the ~/code directory. From there, we can easily create the JSON object Alfred requires.

The equivalent command from go is:

go
1filepath.Glob(fmt.Sprintf("%s/*%s", filepath.Join(home, codeDir), workspaceFileType))

codeDir is the folder in our home directory that contains our workspaces. Now that I’ve found all our workspace files, I need to create JSON objects from them that Alfred will consume.

We’ll define a basic struct to represent that object:

json
1type alfredList struct {
2    Items []alfredItem `json:"items"` // All the items to choose from
3}
4type alfredItem struct {
5    UID          string `json:"uid"`          // ID, just the basename
6    Type         string `json:"type"`         // Type of item, always 'file'
7    Title        string `json:"title"`        // Title to display - friendly name
8    Subtitle     string `json:"subtitle"`     // Subtitle to display - short filepath
9    File         string `json:"arg"`          // Filepath to open if the item is selected
10    Autocomplete string `json:"autocomplete"` // String to use for autocomplete
11}

We can get fancier with our objects, but we’ll keep it simple for now. Our function will create an alfredItem given the file path to a workspace file:

json
1// newAlfredItem creates an alfredItem given the path of a workspace file
2func newAlfredItem(workspaceFile string) alfredItem {
3    // Remove leading path and file extension
4    baseName := strings.Replace(filepath.Base(workspaceFile), workspaceFileType, "", 1)
5
6    return alfredItem{
7        UID:          baseName,
8        Type:         "file",
9        Title:        baseName,
10        Subtitle:     filepath.Join("~", codeDir, baseName), // Use '~' instead of $HOME
11        File:         workspaceFile,
12        Autocomplete: strings.ReplaceAll(baseName, "-", " ") // Split dash-separated words
13  }
14}

So, we want to feed all discovered workflow files into our newAlfredItem method and then print those in the required format. With basic error handling, we end up with this:

json
1matches, err := filepath.Glob(fmt.Sprintf("%s/*%s", filepath.Join(home, codeDir), workspaceFileType))
2if err != nil {
3  log.Fatal(err)
4}
5
6list := alfredList{}
7for _, m := range matches {
8  list.Items = append(list.Items, newAlfredItem(m))
9}
10
11output, err := json.Marshal(list)
12if err != nil {
13  log.Fatal(err)
14}
15fmt.Println(string(output))

Using From Alfred

Create a new blank workflow. In the new workflow, add a Script Filter by selecting Inputs -> Script Filter. We need to give it keywords to bring up the list when we type it. I used ‘vc’ because nothing else was using it.

To get the result of our program into the list of items, we’ll compile our Go program and run the binary from our workflow.

When we run the workflow by entering the keyword vc, we see a list of the discovered workspaces:

We'll open it in VS Code by hitting Enter on a single workspace.

Improvements

Unless we add many workspaces each day, we’ll be fine getting our list from a static-ish JSON file. In the past, I’ve used Lingon to create a job that periodically rediscovers each workspace file and saves them to a JSON file.

Nico Stewart
Nico Stewart
Share:

Related posts

All posts

Get our latest content
in your inbox every week

By subscribing to our Newsletter, you agreed to our Privacy Notice

Community Engagement

Join the Community

Become a part of our thriving community, where you can connect with like-minded individuals, collaborate on projects, and grow together.

Ready to Get Started

Deploy in under 20 minutes with our one line installation script and start configuring your pipelines.

Try it now