elves / elvish

Powerful scripting language & versatile interactive shell
https://elv.sh/
BSD 2-Clause "Simplified" License
5.67k stars 299 forks source link

Support a `[count:x]` wildcard qualifier #849

Open xiaq opened 5 years ago

xiaq commented 5 years ago

Should work similarly to regular expression's {n}, matching number of codepoints, with support for ranges. Examples:

I don't quite like the last example though, as -5 looks like negative five. It is technically unambiguous in this case, but still weird.

xiaq commented 5 years ago

Idea and proposed syntax courtesy of @hanche

krader1961 commented 4 years ago

Rather than introducing another, seldom used, modifier I think allowing a modifier to be a lambda is preferable. Yes, I know I have a PR #1018 (issue #1015) under review to introduce a type: modifier :smile: But I expect that to be used at least two orders of magnitude more often than filtering on the length of of the file name. Allowing a lambda lets the user use Elvish to filter the list of pathnames.

xiaq commented 4 years ago

This is a local qualifier on how many characters a wildcard matches, not a global modifier on the length of the full filename.

krader1961 commented 4 years ago

This is a local qualifier on how many characters a wildcard matches, not a global modifier on the length of the full filename.

Understood, but it is still a niche feature that can be implemented via a callback. The callback can easily test the length of the full path or just the final component.

krader1961 commented 4 years ago

Note that it appears that most of these niche wildcard modifiers exist in bash/ksh/zsh are because those shells don't support a callback to decide if the expansion should be accepted or rejected.

hanche commented 4 years ago

If this is not implemented, I think at least I'd prefer a replacement for likely the most common occurrence: [count:1-] meaning “at least one”. So *[set:ab][nonempty] could match one or more a or b, while ?[set:ab][nonempty] could match exactly one of those.

hanche commented 4 years ago

Here's another issue. How do you write a wildcard pattern that will match filenames containing at least one digit? At present, I don't think you can. But, assuming that a quoted empty string will separate adjacent wildcards, you could say *''*[digit][count:1]* or *''?[digit][nonempty]*. To make it look a little less hacky, we might allow empty modifiers instead: *[]*[digit][count:1]*.

In other shells, this is trivial, as in *[0-9]*. (I have to admit that the wildcards are my least favourite part of the elvish language. But the added power of modifiers is nice, so I am conflicted about them.)

krader1961 commented 4 years ago

@hanche, Can't your "at least one" case be written as *?[set:ab]*? Same for filenames containing at least one digit: *?[digit]*. That works for me:

~/tmp> rm *
~/tmp> touch xay xby xcy a1 b2 c4 
~/tmp> put *?[set:ab]*
▶ a1
▶ b2
▶ xay
▶ xby
~/tmp> put *?[digit]*
▶ a1
▶ b2
▶ c4

More complicated scenarios are more easily, and probably safely, handled using the re: and str: modules in a callback.

I too frequently want to match filenames that contain specific characters but that already seems to be adequately supported. I don't even need all ten fingers to count the number of times in the past twenty years I've needed to do anything more complicated than your "exactly one" or "at least one" cases. When I needed that capability I simply ran the matching filenames through a filter like grep.

hanche commented 4 years ago

Oh sorry, it seems I am being stupid. Hopefully it is temporary. Perhaps due to the discussion of regexps, I conflated the use of ? in wildcards with that in a regexp, thinking of it as “maybe it's there, and maybe not”. My bad. Yes, you're right, that covers it.