cronokirby / alchemy

A discord library for Elixir
MIT License
151 stars 34 forks source link

Cogs: support quoted arguments #32

Closed nhooyr closed 7 years ago

nhooyr commented 7 years ago

My command works like this:

!cmd add "some long text"

Presently, I have to manually extract "some long text" from message.content or use Cogs.set_parser but I think is a very common case that should be addressed in Cogs itself. E.g. I should be able to add another argument to my command function, and It should hold the entire quoted string, not just "some.

cronokirby commented 7 years ago

Sorry for the late reply :P

So, if I get you right, you want to change the default parser, so that it splits on whitespace, but leaves quoted sections intact? so that would make it so that

!foo "bar baz" bar "bar baz"

would represent 3 args. For a single argument, this would just be

Cogs.set_parser(:foo, &List.wrap/1)

but, for larger argument commands, this becomes a bit tedious to write.

This is actually a better default parser tbh, a lot more versatile than just whitespace. I'm planning to add a lot more configurability to a lot of things, so I think what I'll do is make this new parser the default, but also add the option to configure what it would be, for people who don't use this feature.

Probably gonna work on this after voice is sorted out, matter of a day or 2, in the mean time, feel free to work on a PR if you want.

nhooyr commented 7 years ago

I can work on this for sure. I'll have a PR today or tomorrow.

Another issue I was thinking about is a command like

!foo x bar bar

Where bar bar is a single argument. The reason for this is that I think its easier to type in commands without quotes.

One way to support this to check the cogs defined for the command and if the parsed arguments total more than the highest arity cog for the command, we combine as many args into the last argument and choose the highest arity cog.

This feels unclean to me though, so I want to know what you think.

cronokirby commented 7 years ago

The current behaviour of dropping arguments is somewhat intentional

!add 1 3 and the rest doesn't parse

We could make some kind of :parser_drop flag, in the config again, which would make extra text either be dropped off, or agglomerated into one command.

I feel like this and other things would be alleviated by a macro that generates a parser based on a function spec:

Cogs.gen_parser(:add, [:int, :int])
Cogs.def add(a, b), do: Cogs.say "#{a + b}"

Cogs.gen_parser(:foo, [:string, [:string]]

Syntax to be determined, maybe try and get it so that it'd work with anything that defines a protocol allowing it to be read as well. Definitely something to look into...

nhooyr commented 7 years ago

For my PR, I'll keep it simple and implement not splitting spaces in quotes.

cronokirby commented 7 years ago

https://github.com/cronokirby/alchemy/blob/master/lib/Cogs/command_handler.ex#L56

You'll want to change this here; you'll probably need a regex here, or a custom splitter. Something like

"1 2 \"3 3 3\" 4 \"5 5\" "

should be

["1", "2", "3 3 3", "4", "5 5"]

which isn't feasable with a "normal" split

cronokirby commented 7 years ago

https://github.com/cronokirby/alchemy/blob/master/lib/cogs.ex#L515 oh and, you'll need to match it here, if you don't want to break grouped cogs

nhooyr commented 7 years ago

I'm going to write a function to first split on quotes. Then I'll split every even indexed element on spaces because all the odd indexed elements would be quoted elements. Then I have to make sure everything is ordered right.

Also, why is the name for that function cOGS_COMMANDS_GROUPER? shouldn't it be all lowercase?

cronokirby commented 7 years ago

it's to avoid people overwriting it :P, the way grouped cogs work is kinda magic...