Add support for messageRichMessage (tables, lists, code blocks, etc)#552
Open
gabrieltomasin wants to merge 3 commits into
Open
Add support for messageRichMessage (tables, lists, code blocks, etc)#552gabrieltomasin wants to merge 3 commits into
gabrieltomasin wants to merge 3 commits into
Conversation
nchat was showing [UnknownMessage <id>] for Telegram rich messages (tables, lists, code blocks, collapsible details, etc) because TdMessageContentConvert() did not handle the messageRichMessage type. This adds: - GetRichText(): recursively extracts plain text from all RichText variants (bold, italic, links, mentions, custom emoji, etc) - AppendPageBlock(): renders PageBlock types as terminal-friendly text: - Tables -> ASCII aligned with borders - Lists -> bullets with indentation - Code blocks -> preserved formatting - Block quotes -> '> ' prefix - Collapsible details -> header + indented content - Dividers, headers, subheaders, paragraphs - GetRichMessageText(): assembles all blocks into final text - New else-if clause in TdMessageContentConvert() to dispatch messageRichMessage to the new renderer Co-authored-by: Claude Code <noreply@anthropic.com>
The previous implementation used std::string::size() to calculate column widths, which returns byte count, not display width. This caused misaligned tables when cells contained accented characters (é, á, ã) or emoji (✅), since these take more bytes than display columns. Now uses StrUtil::ToWString + StrUtil::WStringWidth (wcswidth) to measure actual terminal display width, and pads cells accordingly. Also fixes separator line to have leading/trailing '+' for proper border.
gabrieltomasin
marked this pull request as ready for review
July 7, 2026 11:32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Telegram recently introduced rich messages (
messageRichMessage), which support advanced formatting like tables, nested lists, code blocks, collapsible sections, block quotes, and more. These are sent by bots and some clients that use the new rich message API.Currently, nchat does not handle this message type — these messages fall through to the default
elsebranch inTdMessageContentConvert()and are displayed as: [UnknownMessage -1243148892]This means any message containing a table, structured list, or other rich content is completely unreadable in nchat.
Solution
This PR adds three private helper functions to
TgChat::Implthat recursively convert rich message content to plain text suitable for terminal display:GetRichText()Recursively extracts plain text from any
RichTextvariant (bold, italic, strikethrough, links, mentions, custom emoji, etc.), preserving the visible text content while discarding formatting markup.AppendPageBlock()Renders
PageBlockelements as terminal-friendly plain text:pageBlockTable+---+borders, usingwcswidthfor correct column sizing with UTF-8pageBlockList-) with indentation for nested itemspageBlockPreformattedpageBlockBlockQuote>prefixpageBlockDetails>(collapsed) orv(open) markerpageBlockDivider---GetRichMessageText()Iterates over all
PageBlocks in arichMessageand assembles the final text string.UTF-8 display width
Table column widths are calculated using
StrUtil::WStringWidth()(which callswcswidth) rather thanstd::string::size(), so accented characters and emoji are sized correctly for terminal alignment.Testing
Built and tested locally against rich messages sent via Telegram bot API. Tables, lists, code blocks, and quotes render correctly in the terminal.
Before:
[UnknownMessage -1243148892]
After (example table):