Home > Software design >  How to globby with findFiles
How to globby with findFiles

Time:09-16

What on Earth is findFiles?

It's in the vscode API documentation you didn't read on file-system support.

Choice of weapons

VS Code is a node application, and so are extensions. Everyone knows this. So the first time we need to manipulate a file, we import fs, which works, and we try some file manipulation, which works. At this point we congratulate ourselves and the VS Code team on transfer of skills, and we stop thinking about it because we know exactly how to do this.

Why would anyone doubt this choice? By all appearances Node fs is an outstanding solution. It's well documented, widely understood and cross-platform. Nothing could possibly go wrong.

Everything has gone wrong

Tempora mutantur, nos et mutamur. Things like Docker and WSL mean that even Windows users on a single host are quite likely to use a remote filesystem. But Node fs, and by extension your extension, only knows about the filesystem in which it was launched.

You need file-system redirection. That implies a proxy at the other end, and some sort of indirection so you can specify which filesystem on what host using which authentication. Once you start thinking about this you wonder why the VS Code team doesn't publish an API for whatever magic they use to do this themselves.

Remember those annoying vscode.Uri objects you have to unpick to get fsPath? The ones returned by all the file system UI interaction events? They have all that metadata in them.

Cut to the chase

If you look at vscode.workspace.fs ("fs"?! that's a clue!) you will find it exports all the methods you need to read and write files and directories. All of these methods take a vscode.Uri. At this point I hope you've connected the dots yourself. Yep, remote filesystem access for the masses (if you can call extension writers the masses).

You still haven't answered the question, Pete: what is findFiles?

Oh. Well. Okay. Right, I expect you all know what globby is and what it's for. Obviously you can't use it on a remote filesystem. And your extension depends on it. Guess what this is for:

findFiles(
  include: GlobPattern, 
  exclude?: GlobPattern | null, 
  maxResults?: number, 
  token?: CancellationToken
): Thenable<Uri[]>

That's globby for remote filesystems, what's your problem?

My problem is it takes a single pattern, not an array of patterns like globby.

While I can work around that by comma separating patterns and surrounding that with curly braces like so {**/*.dll,**/*.exe} that falls apart when the patterns already use this syntax. You're not allowed to nest it. And my users are very likely to want to use patterns like **/*.{exe,dll,pdb,hex,bin,pdf,png,jpg,jpeg,gif,pfx}

So what is it you want, Pete?

So far this is all just you showing off. What were you hoping for in an answer?

Well, the obvious solution is to expand patterns containing expressions into multiple literal expressions, before combining them into a single non-nested expression. But that's boring and hard. I hate writing Regexes.

Or maybe it's not necessary and there's a solution I haven't noticed. I don't know. Help!

CodePudding user response:

[F]alls apart when the patterns already use this syntax. You're not allowed to nest it.

I think what you can do is just process the nested syntax yourself and output non-nested syntax which has the meaning which you require.

E.g. suppose {{a,b},c}x means {a,b}x cx, which then means ax bx cx.

Observe that {a,b,c}x also means ax bx cx and so under this notion of nesting, {{a,b},c} is equivalent to {a,b,c}.

If that's the desired semantics, you can just parse the nested notations in your pattern, and flatten any nesting.

CodePudding user response:

A brace expansion library already exists for Node. It is mysteriously named braces and is available from npm or from its repository on GitHub.

It operates on a string and returns an array of strings. It can expand recursive brace expressions, so a loop is not necessary for my application.

const toxicExcludes = `{${excludes.join(",")}}`; // may contain nested braces
const safeExcludes = `{${braces.expand(toxicExcludes).join(",")}}`; 
  • Related