Files
p f57e8c59d6
Alpine 3.23 Success
Arch Linux AUR Success
OpenBSD 7.8 Success
xC: document the Lua API, bump liberty
asciiman.awk has needed a minor change, and it's forced us into
writing the document in a certain way, but it remains strong.

Looking at the API more closely makes one realise how lacking it is,
but the async functionality is still cool.
2026-07-15 05:47:12 +02:00

10 KiB
Raw Permalink Blame History

xC(1)

Name

xC - terminal-based IRC client

Synopsis

xC [OPTION]…​

Description

xC is a scriptable IRC client for the command line. On the first run it will welcome you with an introductory message. Should you ever get lost, use the /help command to obtain more information on commands or options.

Options

-f, --format

Format IRC text from the standard input, converting colour sequences and other formatting marks to ANSI codes retrieved from the terminfo(5) database:

printf '\x02bold\x02\n' | xC -f

This feature may be used to preview server MOTD files.

-h, --help

Display a help message and exit.

-V, --version

Output version information and exit.

Key bindings

Most key bindings are inherited from the frontend in use, which is either GNU Readline or BSD editline. A few of them, however, are special to the IRC client or assume a different function. This is a list of all local overrides and their respective function names:

M-p

Go up in history for this buffer (normally mapped to C-p).

M-n

Go down in history for this buffer (normally mapped to C-n).

C-p, F5: previous-buffer

Switch to the previous buffer in order.

C-n, F6: next-buffer

Switch to the next buffer in order.

M-TAB: switch-buffer

Switch to the last buffer, i.e., the one you were in before.

M-0, M-1, …​, M-9: goto-buffer

Go to the N-th buffer (normally sets a repeat counter). Since there is no buffer number zero, M-0 goes to the tenth one.

M-!: goto-highlight

Go to the first following buffer with an unseen highlight.

M-a: goto-activity

Go to the first following buffer with unseen activity.

PageUp: display-backlog

Show the in-memory backlog for this buffer using general.pager, which is almost certainly the less(1) program.

M-h: display-full-log

Show the log file for this buffer using general.pager.

M-H: toggle-unimportant

Hide all join, part and quit messages, as well as all channel mode changes that only relate to user channel modes. Intended to reduce noise in channels with lots of people.

M-e: edit-input

Run an editor on the command line, making it easy to edit multiline messages. Remember to save the file before exit.

M-m: insert-attribute

The next key will be interpreted as a formatting mark to insert: c for colours (optionally followed by numbers for the foreground and background), i for italics, b for bold text, u for underlined, s for struck-through, m for monospace, v for inverse text, and o resets all formatting.

C-l: redraw-screen

Should there be any issues with the display, this will clear the terminal screen and redraw all information.

Additionally, C-w and C-u in editline behave the same as they would in Readline or the "vi" command mode, even though the "emacs" mode is enabled by default.

Bindings can be customized in your .inputrc or .editrc file. Both libraries support conditional execution based on the program name. Beware that it is easy to make breaking changes.

Lua plugin API

The API closely reflects the internal structure of the client. For code examples, please consult preinstalled plugins.

All references to internal objects are weak, and may become invalid.

Methods named like :get_PROPERTY can also be accessed as .PROPERTY.

As a rule, properties are read-only, and strings are encoded in UTF-8.

xC.buffers ({Buffer, …​})

All buffers in order.

xC.current_buffer (Buffer)

The active buffer.

xC.global_buffer (Buffer)

The global buffer.

xC.servers ({[string = Server, …​]})

Configured servers, indexed by their name.

xC.get_screen_size() → integer, integer

Return the number of terminal lines and columns.

xC.hook_completion(callback[, priority]) → Hook

Register a generator callback for Tab completions:
Hook, {buffer, line, words, location}, string → {[string, …​]}?

  • buffer (Buffer): Where the completion occurs.

  • line (string): The whole input line.

  • words ({[string, …​]}): The input line split into words.

  • location (integer): Which word is being completed, zero-based.

xC.hook_input(callback[, priority]) → Hook

Register a filter callback for user-typed input:
Hook, Buffer, string → string?

xC.hook_irc(callback[, priority]) → Hook

Register a filter callback for incoming raw IRC messages:
Hook, Server, string → string?

xC.hook_prompt(callback[, priority]) → Hook

Register a generator callback for the TUI input line prompt:
Hook → string?

So as to not break the display, escape any terminal control sequences by enclosing them between \x01 and \x02.

xC.measure(string) → integer

Determine the width of a string in terms of terminal cells.

xC.parse(message) → {tags, prefix, command, params}

Parse a raw IRC message into its components:

  • tags ({[string = string, …​]})

  • prefix (string?)

  • command (string?)

  • params ({[string, …​]})

xC.setup_config(options)

Declare persistent plugin configuration under plugins.NAME, with the name derived from the scripts basename without any extensions. The options index configuration items by name, as further tables with:

  • type (string): The configuration type of the value: one of null, object, boolean, integer, string, string_array.

  • comment (string?): The description of the value.

  • default (string?): The default value, expressed in terms of the configuration language. Items with a default may not become null.

  • on_change (function?): Called when the value is initialized, first read, or later changed.

  • validate (function?): Called to validate values after they pass a type check, returning true if a change should be allowed.

Async Library

Within this concurency model, use Luas coroutine.yield like await.

xC.async.dial(host, service) → WaitChannel

Connect to the server at host, port service. Make sure to set the appropriate callbacks on the returned Connection object.

xC.async.go(fn, …​) → Task

Run fn as a coroutine. These coroutines may only yield WaitChannels. When yielding multiple wait channel values, the operation will return the index of the completed channel, followed by all its return values packed into a single table.

xC.async.timer_ms(milliseconds) → WaitChannel

Resume the calling task after the given number of milliseconds.

Buffer

.channel (Channel?)

The associated channel, if any.

.hide_unimportant (boolean)

Whether unimportant messages are hidden in the user interface.

.highlighted (boolean)

Whether weve been highlighted since last seeing the buffer.

.name (string)

The full name of the buffer.

.new_messages_count (integer)

The number of new messages since last seeing the buffer.

.new_unimportant_count (integer)

How many of those messages are unimportant.

.server (Server?)

The associated server, if any.

.user (User?)

The associated user, if any.

:execute(input)

Process a line of input within the buffer, as if the user typed it in.

:log(message)

Log a status message.

Channel

.left_manually (boolean)

Whether weve left the channel manually, not to rejoin on reconnect.

.name (string)

The channels literal name, which may not be in UTF-8.

.no_param_modes (string)

Active no-parameter channel modes.

.param_modes ({[string = string, …​]})

Active parametrized channel modes.

.topic (string)

The channel topic, which may not be in UTF-8. This string includes any in-line formatting.

.users_len (integer)

The number of users on the channel.

:get_users() → {[{prefixes = string, user = User}, …​]}

Return all users on the channel, together with their prefixes.

Connection

.on_data(data)

Called whenever data is received from the server.

.on_eof()

Called when the connection is closed by the server.

.on_error(error)

Called when the connection sees an error.

:close()

Close the connection.

:send(data)

Send a string to the server.

Hook

:unhook()

Forget about the hook.

Server

.autoaway_active (boolean)

Whether weve currently automatically marked ourselves away.

.buffer (Buffer)

The servers buffer.

.cap_echo_message (boolean)

Whether the echo-message capability is active.

.irc_user_host (string)

Our own users user@host as we know it, used for message splitting.

.manual_disconnect (boolean)

A flag to avoid reconnecting automatically after a manual disconnect request causes a connection interrupt.

.name (string)

The name of the server.

.reconnect_attempt (integer)

Attempt counter while establishing a connection.

//.state (integer)
.user (User?)

Our own user, once were registered.

.user_mode (string)

Our own users modes.

:get_state() → string

The connection state: one of disconnected, connecting, connected, registered, closing, half-closed.

:send(message)

Send an IRC message verbatim, after appending newline characters.

Task

:cancel()

Cancel the task, interrupting any yield.

User

.away (boolean)

Whether the user is marked away.

.nickname (string)

The users literal nickname, which may not be in UTF-8.

:get_channels() → {[Channel, …​]}

Return all channels the user shares with us.

Environment

VISUAL, EDITOR

The editor program to be launched by the edit-input function. If neither variable is set, it defaults to vi(1).

Files

xC follows the XDG Base Directory Specification.

~/.config/xC/xC.conf

The programs configuration file. Preferrably use internal facilities, such as the /set command, to make changes in it.

~/.local/share/xC/logs/

When enabled by general.logging, log files are stored here.

~/.local/share/xC/plugins/
/usr/local/share/xC/plugins/
/usr/share/xC/plugins/

Plugins are searched for in these directories, in order.

Bugs

The editline (libedit) frontend may exhibit some unexpected behaviour.

Reporting bugs

Use https://git.janouch.name/p/xK to report bugs, request features, or submit pull requests.

See also

less(1), readline(3) or editline(7)