@@ 21,13 21,20 @@ usetls is set to true, the **`tls`** module will be used to connect,
instead of the builtin **`socket`** command. If unset, **`socket`**
will be used.
+[Channel metadata](#channel-metadata) is initialized with `proto`,
+`hostname`, `port`, and `uri` set.
+
## `irc::enroll `*`chan ?meta?`*
Sets up the internal state necessary for `chan` to be
-used as an IRC socket. It is called internally by **`irc::connect`**. This
-command is exposed for the use-case where an IRC channel might have a
-more bespoke acquisition process than a simple socket connection.
+used as an IRC socket. It is called internally by **`irc::connect`**.
+This command is exposed for the use-case where an IRC channel might
+have a more bespoke acquisition process than a simple socket
+connection.
+
+`meta` is the initial state of the
+[channel metadata](#channel-metadata).
# Listening to it
@@ 52,7 59,7 @@ Remove the **`fileevent`** wrapper from `chan`. Errors if it is not the
irc wrapper.
-## `irc::listener `*`subcommand chan ?args ...?`*
+## `irc::listener `*`subcommand chan ?arg ...?`*
Configure listener-type event handlers.
@@ 87,7 94,7 @@ that can be passed to **`irc::listener remove`** or **`irc::patlist`**.
Unregisters the listener identified by `id` from `chan`.
-## `irc::handler `*`subcommand chan ?args ...?`*
+## `irc::handler `*`subcommand chan ?arg ...?`*
Configure handler-type event handlers.
@@ 127,7 134,7 @@ executing `script`.
Unregisters the extern handler identified by `id` from `chan`.
-## `irc::extern `*`subcommand chan ?args ...?`*
+## `irc::extern `*`subcommand chan ?arg ...?`*
Configure extern-type event handlers.
@@ 232,6 239,7 @@ PING foo
# matches
```
+
## Event Dispatch Contents
The event dispatch dictionary contains the following properties:
@@ 244,7 252,7 @@ The event dispatch dictionary contains the following properties:
- `srcparts`: the `srcparts` dict, returned from **`irc::src parse`**
- `cmd`: the command of the message
- `params`: the params of the message
-- `meta`: channel metadata, such as server hostname
+
## Dispatch-aliased `irc` Comands
@@ 255,10 263,152 @@ In `listener` and `handlers`, the following commands are aliased:
- `irc::handler`
- `irc::is`
- `irc::listener`
+- `irc::meta`
- `irc::msg`
- `irc::patlist`
- `irc::src`
- `irc::tags`
- `irc::unesc`
-Additionally, the relevant channel is `share`d.
+Additionally, the relevant channel is shared for direct writing.
+
+
+# Channel Metadata
+
+Every channel is initialized with metadata when **`enroll`**ed. This may be
+empty, but it's still there. Metadata is backed with a dict.
+
+
+## `irc::meta `*`subcommand chan ?arg ...?`*
+
+A thin wrapper around **`dict`** commands that routes them to the channel
+metadata dict for `chan`.
+
+### `irc::meta read `*`chan`*
+
+Returns the entire channel metadata dict for `chan`.
+
+### `irc::meta exists `*`chan key ?key ...?`*
+
+A thin wrapper around **`dict exists`**.
+
+### `irc::meta get `*`chan ?key ...?`*
+
+A thin wrapper around **`dict get`**.
+
+### `irc::meta set `*`chan key ?key ...? value`*
+
+A thin wrapper around **`dict set`**.
+
+### `irc::meta unset `*`chan key ?key ...?`*
+
+A thin wrapper around **`dict unset`**.
+
+
+# Parsing
+
+`irc.tcl` exposes a handful of interfaces for parsing IRC primitives.
+
+
+## `irc::tags `*`subcommand ?arg ...?`*
+
+An interface that allows you to treat an IRC tags string like a dict.
+O(n) time complexity, but realistically it will never handle a list of
+more than 3 or 4 so who cares.
+
+All subcommands operate on values, not variables. Escaping and
+unescaping are handled transparently.
+
+### `irc::tags create `*`?key value ...?`*
+
+Creates an IRC tags string from the passed key-value pairs and returns
+it.
+
+Errors if any `key` includes forbidden characters.
+
+### `irc::tags dict `*`tags`*
+
+Converts the passed tags string to a dict with identical members.
+
+### `irc::tags exists `*`tags key`*
+
+Returns true if `tags` includes they key `key`. Returns false
+otherwise.
+
+### `irc::tags get `*`tags ?key?`*
+
+If `key` is set, returns the value associated with it, or an error if
+it does not exist.
+
+If `key` is unset, returns a list of key-value pairs, similar to
+**`dict get`**.
+
+### `irc::tags merge `*`?tags ...?`*
+
+Merges all arguments into one tags string, and returns it. Each `tags`
+may be either a tags string or a dict string.
+
+Errors if any key includes forbidden characters.
+
+### `irc::tags remove `*`tags key`*
+
+Returns a new tags string without `key`.
+
+### `irc::tags set `*`tags key ?value?`*
+
+Returns a new tags string with `key` set to `value`. If value is unset
+or empty, the key is serialized alone, with no equals sign.
+
+Errors if `key` includes forbidden characters.
+
+
+## `irc::is `*`type value`*
+
+A general validation utility for IRC strings. Returns true if `value`
+is a valid string of type `type`. Returns false otherwise.
+
+For more details on how these are implemented, read the
+[Modern IRC Client](https://modern.ircdocs.horse/) and
+[Message Tags](https://ircv3.net/specs/extensions/message-tags.html)
+specifications.
+
+Possible values of `type`:
+
+- `cmd`: an IRC command, e.g. `PRIVMSG` or `421`.
+- `cmd::named`: a named IRC command, e.g. `PRIVMSG`
+- `cmd::numeric`: a numeric IRC status code, e.g. `421`
+- `misc::dict`: a tcl dict, e.g. `foo bar a 1 b 2 c 3 nested {di cts}`
+- `msg::param`: an IRC message parameter, e.g. `#general`
+- `msg::trailing`: an IRC message trailing segment, e.g. `hi guys! :D`
+- `nick`: an IRC nickname, e.g. `aph`
+- `src`: an IRC source, e.g. `aph!~alice@example.com` or
+`irc.example.com`
+- `src::user`: an IRC user source, e.g. `aph!~alice@example.com`
+- `src::servername`: an IRC servername source, e.g. `irc.example.com`
+- `src::part`: a non-nickname part of an IRC source, e.g. `~alice`
+- `tags`: a tags string, e.g.
+`account=aph;time=2024-08-03T23:36:00.320Z`
+- `tags::tag`: an IRC tag string, e.g. `account=aph`
+- `tags::key`: an IRC tags key, e.g. `account`
+- `tags::value`: an IRC tags value, e.g. `aph`
+
+
+## `irc::esc `*`type value`*
+
+Returns `value`, escaped by the rules of `type`.
+
+Possible values of `type`:
+
+- `tags::value`: an IRC tags value, e.g. `aph` or
+`int\smain\s()\n{\n\s\sputs("Hello,\sWorld!")\:\n\s\sreturn\s0\:\n}`
+
+
+## `irc::unesc `*`type value`*
+
+Returns `value`, unescaped by the rules of `type`.
+
+Possible values of `type`:
+
+- `tags::value`: an IRC tags value, e.g. `aph` or
+`int\smain\s()\n{\n\s\sputs("Hello,\sWorld!")\:\n\s\sreturn\s0\:\n}`
+