Feature Request: Script Folders

Would it be possible to add script folders as a feature? Would be useful for connected scripts, modules, etc.

1 Like

Thanks for your feedback. I appreciate it.

This is something I have been working on and I’m hoping to support in future version. All scripts in Scriptable are plain JavaScript files stored on disk and when I add support for folders, I’d like that they are plain folders on disk too. That makes it a bit more complicated to support.

4 Likes

Have you considered using say tags instead of folders?

It could keep a flat structure in a single folder and then you could use a more smart folder like approach with the files appearing in multiple folders if necessary, building smart folders based on the tags. You then still retain the parity with the inbuilt file system as you are simply making use of existing meta data properties.

I don’t know if that would make things simpler or harder to implement, but some sort of filtering via a smart folders sort of approach seems like an evolutionary step above standard folders in terms of flexibility. For users with simple needs a one tag, one folder equation is used. More sophisticated needs are then provided through filters utilising multiple tags and things like last modified date.

I think this is generally a better approach for apps that provide many related elements of executable content. I petitioned the Workflow guys for a few years about implementing this over folders and I still hold out some hope that this is an Apple-y thing to do with Shortcuts.

Just a thought :nerd_face:

3 Likes

… “tags instead of folders” …

Why not do both?

But I would hope/suspect that Files this year would change / break this. :slight_smile:

Because Simon was suggesting some notable complexity to having a folder structure. I was suggesting that tags might be a way to circumvent the complexity.

Both would be better, but one would be better than neither. :wink:

1 Like

I think tags are also a good idea. I had not thought about that. My initial thought is that I like actual folders better but I’ll have to put a bit more thought into it.

The reason I tend to lean towards actual folders is that Scriptable is storing scripts as plain JS files in iCloud Drive (Files appp) and that’s a very deliberate choice. I think it makes Scriptable scripts feel like any other script you could write on any other computer - because that’s what they are! Actual folders would match that philosophy better because, again, that’s how it works on any other computer.

However, the upside of tags is that it’ll probably be easier to implement. Particularly because I’d like folders to have some metadata associated with them, just like scripts have an icon and a color right now.

2 Likes

@simonbs by any chance is there an update to this?
I would love to separate my code into modules and store them separately.

1 Like

Sorry for the late reply. I’ve got a rough implementation on a branch but it’s not ready yet :blush:

1 Like

Thank you!
:heavy_heart_exclamation:

I know it is not beautiful but it does the job. I put all my tool scripts in a folder and I call them:

const fm = FileManager.iCloud()
const dir = fm.documentsDirectory() + "/Tools/"
const alert = importModule('/malAdd/alert')

choice = await alert( "Tool?", "", "",fm.listContents(dir))
tmp = fm.readString(dir + fm.listContents(dir)[choice])
eval("(async () => {" + tmp + "})()")
Script.complete()

And I almost do the same thing with all examples I find and I want to re-use:

const fm = FileManager.iCloud()
const dir = fm.documentsDirectory() + "/Examples/"
const alert = importModule('/malAdd/alert')

choice = await alert( "Exemples", "collectés au fur et à mesure...", "",fm.listContents(dir))
tmp = fm.readString(dir + fm.listContents(dir)[choice])
fm.writeString(fm.documentsDirectory() + "/example2Dev.js", tmp)

Safari.open("scriptable:///run?scriptName=example2Dev")
Script.complete()

I did something like this but didn’t like the idea of using eval(). See reference.

Then I thought, what if they are just modules instead.

/* file: /examples/hello.js */

module.exports = async () => {
  // --- code for the script ---
  await QuickLook.present('hello there')
  // ---
}

scripts in main folder

/* file: examples.js */

async function choose(list) {
  const picker = new Alert()
  list.forEach(i => picker.addAction(i))
  const i = await picker.presentSheet()
  return list[i]
}

const dir = 'examples'

const fm = FileManager.iCloud()
const dirPath = fm.joinPath(fm.documentsDirectory(), dir)
const list = fm.listContents(dirPath)
const sel = await choose(list)
const script = importModule(`${dir}/${sel}`)
await script()

Hi,
I thank do in the same way.
I didn’t like the eval too, that is what I say it is not beautiful.
But, it is my lazy side: I don’t want to modify the scripts I download from everywhere or those I’m modifying.
Perhaps, a day, I will do a tool to transform (add « import module », …) the tools when I need it; perhaps :wink: