Jump to content

Use external text file to populate list filter

Recommended Posts



Im building a little system that allows me to select several items from a list filter and add them as text to a file.

it’s working pretty well, and looping through the list filter several times is actually a pretty neat way to use Alfred.


https://github.com/NeighNeighNeigh/Alfred_TagsFromList/raw/main/Loop - Select multiple options from a list filter.alfredworkflow

What I need to do now is populate the list filter at runtime with the contents of an external plain text file.

for example my tags.txt file might look like this





and each line would become a new entry in the list filter (used for both ‘title’ and ‘arg’)


What’s more is there’s one entry at the top of my list filter that isn’t taken from the external file, and it contains data in the fields ‘title’, ‘subtitle’, and ‘arg’. When selected, this entry is used to finish cycling through the loop (see the linked workflow)

I know that I can use the json node to feed the list filter, but I’m not sure how to convert each line from the source text file into the correctly formatted entries within the json syntax.


Would anyone be able to help me work this out? 

Edited by Floating.Point
Link to comment

While it would be possible by joining a few objects, I recommend you use instead a Script Filter.

Set Language to /usr/bin/osascript (JavaScript), turn on Alfred filters results and use this code (replace the path to the file):


// Correct path between the quotes
const filePath = $("~/Desktop/tags.txt").stringByExpandingTildeInPath.js

// Leave unchanged from here
const fileData = $.NSFileManager.defaultManager.contentsAtPath(filePath)
const fileContents = $.NSString.alloc.initWithDataEncoding(fileData, $.NSUTF8StringEncoding).js

const sfItems = fileContents
  .map(item => ({ title: item, arg: item }))

JSON.stringify({ items: sfItems })


Link to comment

Thanks Vitor, for jumping in on this one. 


Your script filter is fantastic – successfully grabbing lines from the file to populate the menu.

The next section is me troubleshooting as I better explain the requirement, try and deconstruct your script, and fail to integrate the required functionality.


Note: There is a concise TLDR at the end.


I see that .splice(1) is removing the first line. Forgive me, but in hindsight I didn't do a great job of explaining what's actually going on there.


Put simply, the very first item in the menu needs to be the following (JSON):

{\"imagefile\":\"myicon.png\",\"title\":\"Finished tagging\",\"arg\":\"Done\",\"subtitle\":\"{var:displayTags}\"}  

(which I extracted from the original List Filter using Alfred's 'Copy Configuration' tool (A trick I learned from you 😊


Attempting to deconstruct your script and implement the above, I have first removed the .splice(1) line as it is not needed.

Next I can see that the final line seems to be populating something called 'items'. I recognise that from the JSON that came out of the 'Copy Configuration' of the List Filter. So my instinct is that I just need to add my custom line of JSON to 'items' before the 'sfItems' constant is fed into it…


// Correct path between the quotes
const filePath = $("/Users/nathan/Documents/Notes/Databases/References/Metadata/Tag List.md").stringByExpandingTildeInPath.js

// Leave unchanged from here
const fileData = $.NSFileManager.defaultManager.contentsAtPath(filePath)
const fileContents = $.NSString.alloc.initWithDataEncoding(fileData, $.NSUTF8StringEncoding).js

const sfItems = fileContents
  .map(item => ({ title: item, arg: item }))

JSON.stringify({ items: {\"imagefile\":\"myicon.png\",\"title\":\"Finished tagging\",\"arg\":\"Done\",\"subtitle\":\"{var:displayTags}\"}, sfItems })

Sadly, this throws the following error: syntaxError: Invalid escape in identifier: '\' (-2700) 


So now I've been hacking away trying to resolve the syntax error.


I've tried wrapping it in quotes like so:

JSON.stringify({ items: "{\"imagefile\":\"myicon.png\",\"title\":\"Finished tagging\",\"arg\":\"Done\",\"subtitle\":\"{var:displayTags}\"}," sfItems })

 result: SyntaxError: Unexpected identifier 'sfItems'. Expected '}' to end an object literal. (-2700)


Tried removing all the escaping and keeping it in quotes:

JSON.stringify({ items: "{imagefile:myicon.png,title:Finished tagging,arg:Done,subtitle:{var:displayTags}}," sfItems })

result: Same error as above


I've tried these, among other fruitless (likely silly) attempts, and don't really know what to try next.


So again, what I'm trying to figure out is the following:



The first entry in the list needs to use the following JSON (I extracted with the 'copy configuration' tool). All other entries are populated from the text file.

{\"imagefile\":\"myicon.png\",\"title\":\"Finished tagging\",\"arg\":\"Done\",\"subtitle\":\"{var:displayTags}\"}  


Thanks for your tuition and patience, it's insanely helpful!

Link to comment

The configuration JSON from an object is not the same as the JSON interpreted from a Script Filter (see docs).

Seeing as you’re reading an environment variable, that also needs to be taken into account. Try this:


// Correct path between the quotes
const filePath = $("~/Documents/Notes/Databases/References/Metadata/Tag List.md").stringByExpandingTildeInPath.js

// Leave unchanged from here
const theTags = $.NSProcessInfo.processInfo.environment.objectForKey("displayTags").js
const fileData = $.NSFileManager.defaultManager.contentsAtPath(filePath)
const fileContents = $.NSString.alloc.initWithDataEncoding(fileData, $.NSUTF8StringEncoding).js

const topItem = [{ title: "Finished tagging", arg: "Done", subtitle: theTags }]
const sfItems = fileContents.split("\n").map(item => ({ title: item, arg: item }))

JSON.stringify({ items: topItem.concat(sfItems) })


Link to comment

This is working very well, thank you Vitor. The script filter took me a bit outside my comfort zone, which was a fun adventure. After implementing your fine work, I used the resource you linked and learned how script filters handle icons. Then I felt I had at least contributed something to the final solution by successfully adding in my custom icon for the 'finished tagging' entry. It's all working great!


Thank you again 🙏

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...