Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
81ef012
feat: allow message introspection
Nerixyz Jul 22, 2025
6140f6a
chore: rerun tests
Nerixyz Aug 1, 2025
ec84f0b
fixup! plugin meta
Nerixyz Aug 1, 2025
ec9fc27
chore: changelog
Nerixyz Aug 1, 2025
2538ec5
fix: document `add_flags`
Nerixyz Aug 1, 2025
8bd7fc4
fix: more elements
Nerixyz Aug 1, 2025
49f3a98
fix: const-ref
Nerixyz Aug 1, 2025
4352c6a
Merge remote-tracking branch 'upstream/master' into feat/message-intr…
Nerixyz Aug 4, 2025
0886f40
chore: remove debug thing
Nerixyz Aug 4, 2025
86327ed
fix: use MessgeColor::fromLua
Nerixyz Aug 9, 2025
4474d1f
fix: use a TYPE constant for message types
Nerixyz Aug 9, 2025
08cd2cb
test: seaprate flag and other tests
Nerixyz Aug 9, 2025
d690ff2
refactor: return `nil` for non existing properties
Nerixyz Aug 9, 2025
8c37eb0
test: add a few more tests
Nerixyz Aug 9, 2025
d33eb2d
docs: update types
Nerixyz Aug 9, 2025
dd106e6
try: maybe gcc likes this more?
Nerixyz Aug 9, 2025
58e3e3d
fix: comment
Nerixyz Aug 10, 2025
8a24688
Merge remote-tracking branch 'upstream/master' into feat/message-intr…
Nerixyz Aug 10, 2025
9941457
Merge remote-tracking branch 'upstream/master' into feat/message-intr…
Nerixyz Oct 2, 2025
dbb0aa9
Merge remote-tracking branch 'upstream/master' into feat/message-intr…
Nerixyz Oct 2, 2025
b3a82ad
fix: link stuff
Nerixyz Oct 2, 2025
58ff358
fix: changelog
Nerixyz Oct 2, 2025
4bdd417
Merge remote-tracking branch 'upstream/master' into feat/message-intr…
Nerixyz Nov 22, 2025
addb49e
fix: `this` and ptr-to-member-fn
Nerixyz Dec 5, 2025
bb50f14
docs(plugins): document and test message introspection
Nerixyz Dec 5, 2025
0af2b90
Merge remote-tracking branch 'upstream/master' into feat/message-intr…
Nerixyz Dec 5, 2025
fcdc0c4
Merge branch 'master' into feat/message-introspection
Mm2PL Dec 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Minor: Badges now link to their home page like emotes in the context menu. (#6437)
- Minor: Fixed usercard resizing improperly without recent messages. (#6496)
- Minor: Added setting for character limit of deleted messages. (#6491)
- Minor: Added message introspection and manipulation. (#6353)
- Minor: Added link support to plugin message API. (#6386, #6527)
- Minor: Added a description for the logging option under moderation tab. (#6514)
- Minor: Added a JSON API for plugins (`require('chatterino.json')`). (#6420)
Expand Down
126 changes: 125 additions & 1 deletion docs/chatterino.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,24 @@ declare namespace c2 {
var WebSocket: WebSocketConstructor;

interface Message {
__dummy: void; // avoid being an empty interface
flags: MessageFlag;
id: string;
parse_time: number;
search_text: string;
message_text: string;
login_name: string;
display_name: string;
localized_name: string;
user_id: string;
channel_name: string;
username_color: string;
server_received_time: number;
highlight_color: string | null;
frozen: boolean;
elements(): MessageElement[];
append_element(init: MessageElementInit): void;
}

interface MessageConstructor {
new: (this: void, init: MessageInit) => Message;
}
Expand All @@ -184,6 +200,14 @@ declare namespace c2 {
elements?: MessageElementInit[];
}

interface MessageElementBase {
flags: MessageElementFlag;
tooltip: string;
trailing_space: boolean;
link: Link;
add_flags(flags: MessageElementFlag): void;
}

interface MessageElementInitBase {
tooltip?: string;
trailing_space?: boolean;
Expand All @@ -192,6 +216,25 @@ declare namespace c2 {

type MessageColor = "text" | "link" | "system" | string;

type MessageElement =
| TextElement
| SingleLineTextElement
| MentionElement
| TimestampElement
| TwitchModerationElement
| LinebreakElement
| ReplyCurveElement
| LinkElement
| EmoteElement
| LayeredEmoteElement
| ImageElement
| CircularImageElement
| ScalingImageElement
| BadgeElement
| ModBadgeElement
| VipBadgeElement
| FfzBadgeElement;

type MessageElementInit =
| TextElementInit
| SingleLineTextElementInit
Expand All @@ -201,6 +244,13 @@ declare namespace c2 {
| LinebreakElementInit
| ReplyCurveElementInit;

interface TextElement extends MessageElementBase {
type: "text";
words: string[];
color: string;
style: c2.FontStyle;
}

interface TextElementInit extends MessageElementInitBase {
type: "text";
text: string;
Expand All @@ -209,6 +259,13 @@ declare namespace c2 {
style?: FontStyle;
}

interface SingleLineTextElement extends MessageElementBase {
type: "single-line-text";
words: string[];
color: string;
style: c2.FontStyle;
}

interface SingleLineTextElementInit extends MessageElementInitBase {
type: "single-line-text";
text: string;
Expand All @@ -217,6 +274,14 @@ declare namespace c2 {
style?: FontStyle;
}

interface MentionElement extends Omit<TextElement, "type"> {
type: "mention";
display_name: string;
login_name: string;
fallback_color: string;
user_color: string;
}

interface MentionElementInit extends MessageElementInitBase {
type: "mention";
display_name: string;
Expand All @@ -225,24 +290,83 @@ declare namespace c2 {
user_color: MessageColor;
}

interface TimestampElement extends MessageElementBase {
type: "timestamp";
time: number;
}

interface TimestampElementInit extends MessageElementInitBase {
type: "timestamp";
time?: number;
}

interface TwitchModerationElement extends MessageElementBase {
type: "twitch-moderation";
}

interface TwitchModerationElementInit extends MessageElementInitBase {
type: "twitch-moderation";
}

interface LinebreakElement extends MessageElementBase {
type: "linebreak";
}

interface LinebreakElementInit extends MessageElementInitBase {
type: "linebreak";
flags?: MessageElementFlag;
}

interface ReplyCurveElement extends MessageElementBase {
type: "reply-curve";
}

interface ReplyCurveElementInit extends MessageElementInitBase {
type: "reply-curve";
}

interface LinkElement extends Omit<TextElement, "type"> {
type: "link";
lowercase: string;
original: string;
}

interface EmoteElement extends MessageElementBase {
type: "emote";
}

interface LayeredEmoteElement extends MessageElementBase {
type: "layered-emote";
}

interface ImageElement extends MessageElementBase {
type: "image";
}

interface CircularImageElement extends MessageElementBase {
type: "circular-image";
}

interface ScalingImageElement extends MessageElementBase {
type: "scaling-image";
}

interface BadgeElement extends MessageElementBase {
type: "badge";
}

interface ModBadgeElement extends Omit<BadgeElement, "type"> {
type: "mod-badge";
}

interface VipBadgeElement extends Omit<BadgeElement, "type"> {
type: "ffz-badge";
}

interface FfzBadgeElement extends Omit<BadgeElement, "type"> {
type: "ffz-badge";
}

interface Link {
type: LinkType;
value: string;
Expand Down
140 changes: 120 additions & 20 deletions docs/lua-meta/globals.lua
Original file line number Diff line number Diff line change
Expand Up @@ -299,34 +299,31 @@ function c2.HTTPRequest.create(method, url) end
-- Begin src/controllers/plugins/api/Message.hpp


---A chat message
---@class c2.Message
c2.Message = {}

---A table to initialize a new message
---@class MessageInit
---@field flags? c2.MessageFlag Message flags (see `c2.MessageFlags`)
---@field id? string The (ideally unique) message ID
---@field parse_time? number Time the message was parsed (in milliseconds since epoch)
---@field search_text? string Text to that is compared when searching for messages
---@field message_text? string The message text (used for filters for example)
---@field login_name? string The login name of the sender
---@field display_name? string The display name of the sender
---@field localized_name? string The localized name of the sender (this is used for CJK names, otherwise it's empty)
---@field user_id? string The ID of the user who sent the message
---@field channel_name? string The name of the channel this message appeared in
---@field username_color? string The color of the username
---@field server_received_time? number The time the server received the message (in milliseconds since epoch)
---@field highlight_color? string|nil The color of the highlight (if any)
---@field elements? MessageElementInit[] The elements of the message
---@class c2.MessageElementBase
---@field flags c2.MessageElementFlag The element's flags
---@field tooltip string The tooltip (if any)
---@field trailing_space boolean Whether to add a trailing space after the element
---@field link c2.Link An action when clicking on this element. Mention and Link elements don't support this. They manage the link themselves.
c2.MessageElementBase = {}
-- ^^^ this is kinda fake - this table doesn't exist in Lua, we only declare it to add methods

--- Add flags to this element
---
---@param flags c2.MessageElementFlag
function c2.MessageElementBase:add_flags(flags) end

---A base table to initialize a new message element
---@class MessageElementInitBase
---@field tooltip? string Tooltip text
---@field trailing_space? boolean Whether to add a trailing space after the element (default: true)
---@field link? c2.Link An action when clicking on this element. Mention and Link elements don't support this. They manage the link themselves.

---@alias MessageColor "text"|"link"|"system"|string A color for a text element - "text", "link", and "system" are special values that take the current theme into account
---@class c2.TextElement : c2.MessageElementBase
---@field type "text"
---@field words string[] The words of this element
---@field color string The color of the text
---@field style c2.FontStyle The font style of the text

---A table to initialize a new message text element
---@class TextElementInit : MessageElementInitBase
Expand All @@ -336,6 +333,12 @@ c2.Message = {}
---@field color? MessageColor The color of the text
---@field style? c2.FontStyle The font style of the text

---@class c2.SingleLineTextElement : c2.MessageElementBase
---@field type "single-line-text"
---@field words string[] The words of this element
---@field color string The color of the text
---@field style c2.FontStyle The font style of the text

---A table to initialize a new message single-line text element
---@class SingleLineTextElementInit : MessageElementInitBase
---@field type "single-line-text" The type of the element
Expand All @@ -344,6 +347,12 @@ c2.Message = {}
---@field color? MessageColor The color of the text
---@field style? c2.FontStyle The font style of the text

---@class c2.MentionElement : c2.TextElement
---@field type "mention"
---@field login_name string The login name of the mentioned user
---@field fallback_color MessageColor The color of the element in case the "Colorize @usernames" is disabled
---@field user_color MessageColor The color of the element in case the "Colorize @usernames" is enabled

---A table to initialize a new mention element
---@class MentionElementInit : MessageElementInitBase
---@field type "mention" The type of the element
Expand All @@ -352,26 +361,117 @@ c2.Message = {}
---@field fallback_color MessageColor The color of the element in case the "Colorize @usernames" is disabled
---@field user_color MessageColor The color of the element in case the "Colorize @usernames" is enabled

---@class c2.TimestampElement : c2.MessageElementBase
---@field type "timestamp"
---@field time number The time of the timestamp (in milliseconds since epoch).

---A table to initialize a new timestamp element
---@class TimestampElementInit : MessageElementInitBase
---@field type "timestamp" The type of the element
---@field time number? The time of the timestamp (in milliseconds since epoch). If not provided, the current time is used.

---@class c2.TwitchModerationElement : c2.MessageElementBase
---@field type "twitch-moderation"

---A table to initialize a new Twitch moderation element (all the custom moderation buttons)
---@class TwitchModerationElementInit : MessageElementInitBase
---@field type "twitch-moderation" The type of the element

---@class c2.LinebreakElement : c2.MessageElementBase
---@field type "linebreak"

---A table to initialize a new linebreak element
---@class LinebreakElementInit : MessageElementInitBase
---@field type "linebreak" The type of the element
---@field flags? c2.MessageElementFlag Message element flags (see `c2.MessageElementFlags`)

---@class c2.ReplyCurveElement : c2.MessageElementBase
---@field type "reply-curve"

---A table to initialize a new reply curve element
---@class ReplyCurveElementInit : MessageElementInitBase
---@field type "reply-curve" The type of the element

---@class c2.LinkElement : c2.TextElement
---@field type "link"

---@class c2.EmoteElement : c2.MessageElementBase
---@field type "emote"

---@class c2.LayeredEmoteElement : c2.MessageElementBase
---@field type "layered-emote"

---@class c2.ImageElement : c2.MessageElementBase
---@field type "image"

---@class c2.CircularImageElement : c2.MessageElementBase
---@field type "circular-image"

---@class c2.ScalingImageElement : c2.MessageElementBase
---@field type "scaling-image"

---@class c2.BadgeElement : c2.MessageElementBase
---@field type "badge"

---@class c2.ModBadgeElement : c2.BadgeElement
---@field type "mod-badge"

---@class c2.VipBadgeElement : c2.BadgeElement
---@field type "vip-badge"

---@class c2.FfzBadgeElement : c2.BadgeElement
---@field type "ffz-badge"

---@alias MessageElement c2.TextElement|c2.SingleLineTextElement|c2.MentionElement|c2.TimestampElement|c2.TwitchModerationElement|c2.LinebreakElement|c2.ReplyCurveElement|c2.LinkElement|c2.EmoteElement|c2.LayeredEmoteElement|c2.ImageElement|c2.CircularImageElement|c2.ScalingImageElement|c2.BadgeElement|c2.ModBadgeElement|c2.VipBadgeElement|c2.FfzBadgeElement
---@alias MessageElementInit TextElementInit|SingleLineTextElementInit|MentionElementInit|TimestampElementInit|TwitchModerationElementInit|LinebreakElementInit|ReplyCurveElementInit

---A chat message
---@class c2.Message
---@field flags c2.MessageFlag The message's flags
---@field parse_time number Time the message was parsed (in milliseconds since epoch)
---@field id string The message ID
---@field search_text string Text to check when searching for messages
---@field message_text string Text content of this message (used for filters for example)
---@field login_name string The login name of the sender
---@field display_name string The dispay name of the sender
---@field localized_name string The localized name of the sender (this is used for CJK names, otherwise it's empty)
---@field user_id string The ID of the sender
---@field channel_name string The name of the channel this message appeared in
---@field username_color string The color of the username
---@field server_received_time number The time the server received the message (in milliseconds since epoch)
---@field highlight_color string The color of the highlight or empty
---@field frozen boolean If this is set, Lua plugins can't modify this message (as it's visible to the user).
c2.Message = {}

--- The elements this message is made up of
---
---@return MessageElement[] elements
function c2.Message:elements() end

--- Add an element to this message.
---
---@param init MessageElementInit The element to add
function c2.Message:append_element(init) end

---A table to initialize a new message
---@class MessageInit
---@field flags? c2.MessageFlag Message flags (see `c2.MessageFlags`)
---@field id? string The (ideally unique) message ID
---@field parse_time? number Time the message was parsed (in milliseconds since epoch)
---@field search_text? string Text to that is compared when searching for messages
---@field message_text? string The message text (used for filters for example)
---@field login_name? string The login name of the sender
---@field display_name? string The display name of the sender
---@field localized_name? string The localized name of the sender (this is used for CJK names, otherwise it's empty)
---@field user_id? string The ID of the user who sent the message
---@field channel_name? string The name of the channel this message appeared in
---@field username_color? string The color of the username
---@field server_received_time? number The time the server received the message (in milliseconds since epoch)
---@field highlight_color? string|nil The color of the highlight (if any)
---@field elements? MessageElementInit[] The elements of the message

---@alias MessageColor "text"|"link"|"system"|string A color for a text element - "text", "link", and "system" are special values that take the current theme into account

--- Creates a new message
---
---@param init MessageInit The message initialization table
Expand Down
Loading
Loading