Jump to content
luckman212

[SOLVED] JSON Config - ??? so confused

Recommended Posts

Guys, can anyone help me out? I'm trying to use a `JSON Config` object to set some variables in my workflow. But it's not working. I've read https://www.alfredapp.com/help/workflows/utilities/json/ and done as much googl'ing as I can. I made a simple test workflow that illustrates my dilemma. When setting args using `Args and Vars` (hold SHIFT) it works, but the JSON Config seemingly does nothing.

 

Download below:

JSONConfig.alfredworkflow (github)
 

Any ideas?

 

image.png.a24ef412448d1b104281d7629ebc49e1.png

Edited by luckman212

Share this post


Link to post
2 hours ago, luckman212 said:

I've read https://www.alfredapp.com/help/workflows/utilities/json/ and done as much googl'ing as I can.

 

You need to read more carefully ;) This is the example from that page:

{
  "alfredworkflow" : {
    "arg" : "{query}",
    "config" : {
    },
    "variables" : {
    }
  }
}

Notice that variables is a sibling of config, not a child. Also, there is no argument field.


The config object contains settings for the following workflow element. It is a separate thing.

 

This is your JSON:

{
  "alfredworkflow" : {
    "config" : {
      "argument" : "",
      "variables" : {
        "a" : "apple",
        "b" : "ball",
        "c" : "chips"
      }
    }
  }
}

This is the correct JSON:

{
  "alfredworkflow" : {
    "arg" : "{query}",
    "config" : {
    },
    "variables" : {
      "a" : "apple",
      "b" : "ball",
      "c" : "chips"
    }
  }
}

 

Edited by deanishe

Share this post


Link to post

Wow, thanks @deanishe 🤘

Ok so here's where I got tripped up—

I right clicked on the configured "Args and Vars" object and selected "Copy Configuration"

Then I pasted that into the JSON Config object, and it gives me this:

{
  "alfredworkflow" : {
    "config" : {
      "argument" : "",
      "variables" : {
        "c" : "chips",
        "a" : "apple",
        "b" : "ball"
      }
    }
  }
}

As you noted, this seems to be incorrect/nonfunctional. So, not sure if this is intended behavior, or a bug...

 

Share this post


Link to post
3 minutes ago, luckman212 said:

I right clicked on the configured "Args and Vars" object and selected "Copy Configuration"

 

Ah, right. Well, the Arg and Vars object does have variables in its configuration.


The config object is element-specific, though. What works with Arg and Vars won't work with other elements.

 

But I can see how that would lead to confusion.

Share this post


Link to post
5 minutes ago, deanishe said:

I can see how that would lead to confusion.

 

Yep. That's what got me. A couple of example workflows featuring the JSON Object would have gone a long way. Thanks again for your help!!

 

Share this post


Link to post
Just now, luckman212 said:

A couple of example workflows featuring the JSON Object would have gone a long way.

 

The docs in general would benefit from a bit more depth. It's also just dumb bad luck that you copied the config from an Arg and Vars element. Anything else, and you'd have had the "right" JSON. But you picked the only one (AFAIK) that doesn't have the standard arg and variables fields.

Share this post


Link to post

@deanishe sorry to ask, but could you possibly nudge me in the right direction on this?

 

I'm trying to dynamically generate the JSON to set variables using a Script Action (ruby). Got this:

require 'json'

json = []
cc = 20

for i in 0..cc do
  varname = 'clip' + (i).to_s
  clipname = '{clipboard:' + (i).to_s + '}'
  json.push( varname => clipname )
end

puts({ "alfredworkflow" => { "arg" => "{query}", "variables" => json }}.to_json)

Which generates almost the right output, but not quite (the variables are output as independent items in []'s instead of as direct descendants of `variables`. Any idea what I'm doing wrong here?

Share this post


Link to post
8 minutes ago, luckman212 said:

Any idea what I'm doing wrong here?

 

I don't know Ruby, so I'm just guessing, but it looks like you're setting variables to an array, not to a hash. This line json = [] should be json = {}, and json.push( varname => clipname ) should be json[varname] = clipname.

 

Share this post


Link to post

@deanishe that worked! :D So the script is:

 

require 'json'

json = {}
cc = 20

for i in 0..cc do
  varname = 'clip' + (i).to_s
  clipname = '{clipboard:' + (i).to_s + '}'
  json[varname] = clipname
end

puts({ "alfredworkflow" => { "arg" => "{query}", "variables" => json }}.to_json)

So now the script generates "perfect" output, BUT instead of substituting {query} and {clipboard:1} etc. values, Alfred is setting these as literal values. E.g. instead of the actual query or clipboard history contents, I'm getting the literal text "{clipboard:1}".

 

edit: here's a python version of the same script, also suffers from the same problem of non-substituted variables

import json, os

obj = {}
j = {}
varlist = {}

cc = int(os.getenv('CLIP_COUNT', 3))

for i in range(cc):
  varname = 'clip' + str(i)
  clipname = '{clipboard:' + str(i) + '}'
  varlist[varname] = clipname

j['variables'] = varlist
j['arg'] = '{query}'
obj['alfredworkflow'] = j
print json.dumps(obj)

Seems impossible that this would be the way the Dynamic Placeholders feature was designed. Do I need to ask @Andrew ?

Edited by luckman212

Share this post


Link to post
2 hours ago, luckman212 said:

Seems impossible that this would be the way the Dynamic Placeholders feature was designed

 

That's exactly how it's designed. From that page:

 

Quote

Alfred offers dynamic placeholders, which allow you to insert dynamically-created content when using Snippets and in certain workflow objects.

 

Alfred—quite rightly—doesn't mess with the output from your scripts.

 

What exactly are you trying to achieve?

Share this post


Link to post
11 minutes ago, deanishe said:

What exactly are you trying to achieve?

 

Trying to create a workflow that references items from the clipboard history (up to 25, 50, or more). So I want to set up the variables programmatically via a loop vs. tediously like

{
  "alfredworkflow" : {
    "variables" : {
      ...
      "clip30" : "{clipboard:30}",
      "clip31" : "{clipboard:31}",
      "clip32" : "{clipboard:32}",
      "clip33" : "{clipboard:33}",
      "clip34" : "{clipboard:34}",
      ...
    }
  }
}

 

Share this post


Link to post
27 minutes ago, luckman212 said:

Trying to create a workflow that references items from the clipboard history (up to 25, 50, or more). So I want to set up the variables programmatically via a loop vs. tediously like

 

That's not what you're trying to achieve, that's how you're trying to achieve it.

 

What is the end goal here?

Share this post


Link to post

Ok, well the end goal is a workflow that displays the most recent N clipboard history items and upon selecting one, "types" it to the foreground app by simulating keystrokes (AppleScript `keystroke`). The reason for this to exist is e.g. some websites don't allow copy/paste so you want to "type" something into a field. Or Remote Desktop / ARD / other remote control sessions where a "paste" doesn't always work. This might not be useful for many people but I use it all the time.

 

Here's the workflow as it stands if you want to see:

https://github.com/luckman212/alfredworkflows/blob/master/Type.alfredworkflow.zip?raw=true

 

Share this post


Link to post
6 hours ago, luckman212 said:

This might not be useful for many people but I use it all the time.

 

I use it quite a lot, too.

 

The best way to get the clipboard history is to read it from Alfred's clipboard database. It's a *little* hacky, but I've seen Andrew recommend people do it this way, so it's pretty safe. Also, it's extremely fast.

from contextlib import contextmanager
import os
import sqlite3

# Number of clipboard items to retrieve
COUNT = 10

# Path to clipboard history database
# For Alfred 3, replace "Alfred" with "Alfred 3"
dbpath = os.path.expanduser('~/Library/Application Support/Alfred/Databases/clipboard.alfdb')


@contextmanager
def database(path):
    """Open and close database."""
    db = sqlite3.connect(path)
    yield db
    db.close()

clips = []
with database(dbpath) as db:
    # each row is a tuple, even though we're only selecting one column
    rows = db.execute('SELECT item FROM clipboard ORDER BY ts DESC LIMIT ' + str(COUNT))
    clips = [row[0] for row in rows]

for s in clips:
    print(s)

 

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...