Posting multi-line messages
Opened this issue · 8 comments
Hi! I am currently writing an IRC bot (located at Queertoo/Alher) based on Beamie, and for the needs of various plugins (especially for the Urban Dictionary), I need to transmit a message overt multiple lines.
What would be the best solution? Hacking in chatty's core or hacking at the plugin/hook level?
Hi. Chatty needs to support multi-line messages, I'll work on that.
In the meantime, you can return a list of messages from a hook like so:
defmodule MyHook do
def run(_sender, _message) do
text = """
My
multiline
message
"""
text
|> String.split("\n")
|> Enum.map(&{:msg, &1})
end
end
Ooooooh :D. You're lovely, thank you! ❤️
An interesting feature would be, in the case of a :reply, to hilight the sender in the first message and then to paste the rest of the message over multiple lines without highlighting them. :)
According to RFC 2812
IRC messages are always lines of characters terminated with a CR-LF
(Carriage Return - Line Feed) pair, and these messages SHALL NOT
exceed 512 characters in length, counting all characters including
the trailing CR-LF. Thus, there are 510 characters maximum allowed
for the command and its parameters. There is no provision for
continuation of message lines
I think it may help =)
And here is my version :
def run(_sender, msg) do
case String.downcase(msg) do
"!define " <> term ->
get_def(term)
|> String.split_at(449)
|> Tuple.to_list
|> Enum.map(fn(x) -> {:msg, x} end)
_ -> nil
end
end
This code has however a major drawback. Because Only the first half of the message is guaranteed to be inferior to 450 characters, but not the other half.
I've been told to use a recursive function to split the string into multiple strings in a list, but I can't figure out how to do that (though it may be stupid as hell…).
And thanks to the support of @ephe-meral, a working version is now in production:
def run(_sender, msg) do
case String.downcase(msg) do
"!define " <> term ->
get_def(term) |> send_msg
_ -> nil
end
end
def get_def(term) do
definition = Chatty.Plugin.UrbanDict.what_is(term)
case definition do
:nodef ->
"Sorry, there are no definitions for \""<> term <>"\" :("
_ ->
definition
end
end
def send_msg(msg) do
msg
|> split_at_rec(449)
|> Enum.map(fn(x) -> {:msg, x} end)
end
def split_at_rec(string, at) when at > 0,
do: split_at_rec(string, at, []) |> Enum.reverse
def split_at_rec(string, at, acc) do
case string |> String.split_at(at) do
{"", ""} -> acc
{a, ""} -> [a | acc]
{a, b} -> split_at_rec(b, at, [a | acc])
end
end
We will be working on an improvement to avoid 'middle-of-a-word-splitting', and then I think it should be mergeable in the core of Chatty. :)
I have the following preliminary plan:
- provide built-in support for multi-line messages in hooks, sending each line as a separate IRC message. If a message has a recipient, only the first line will include the name.
- implement splitting of IRC messages at spaces so that each message fits into the maximum message limit (will be adjustable, also with the ability to specify the absolute limit, beyond which the message will simply be truncated). This will be implemented for
PRIVMSG
andNOTICE
messages at the IRC protocol level.
Implemented multi-line messages in master. Now you don't need to do anything special in your hook implementation, the following should work as expected:
defmodule MyHook do
def run(_, _) do
{:reply, """
Have
a
nice
day
"""}
end
end
Thanks :)
However, the patch doesn't seem to support long messages splitting (which is what @ephe-meral and I intendend to support in Queertoo/Alher an explained in #5 (comment). I think you might be interested by UrbanHook which brings an interesting way to support 'more-than-450-chars-messages'.