fix(messages): convert Markdown to Slack mrkdwn on send (closes #1) - #3
Merged
Conversation
'messages send' defaults to --format markdown but did no conversion, so standard Markdown (**bold**, [text](url), lists) rendered as literal characters in Slack. Add a dependency-free Markdown->mrkdwn converter (src/utils/mrkdwn.rs) applied on the send path: - **bold**/__bold__ -> *bold*; *italic*/_italic_ -> _italic_; ~~s~~ -> ~s~ - # heading -> bold line; [t](url)/ -> <url|t> - bullets -/*/+ -> '• '; ordered 1./1) -> normalized '1. ' - inline code, fenced code, and existing <@U…>/<url|text> spans preserved --format plain still sends verbatim with mrkdwn disabled. 24 converter unit tests + docs (README, skill). Verified live against a real workspace.
Web API requests are sent as application/x-www-form-urlencoded (since the form-encoding change on main), but test_files_list_in_channel still matched a PartialJson body. The mock never matched, the request errored, and the test panicked under SLACK_INTEGRATION_TESTS=1 (CI). Switch to a UrlEncoded matcher. This was failing on main and on every open PR's Test/Coverage jobs.
…nmatched ** Four bugs flagged by the Sentry bug-prediction reviewer on #3: 1. Spaced asterisks (a * b * c) were wrongly italicized. Add simplified CommonMark flanking: a single * only opens emphasis when not followed by whitespace and only closes when not preceded by whitespace (find_emphasis_close). 2. Angle brackets were greedily preserved, so <...> around comparisons (x < 5 and **bold** > 2) blocked conversion. Only preserve when the content is a real mrkdwn span — mention (@/#/!) or scheme URL (is_mrkdwn_span); otherwise emit < literally and keep converting. 3. parse_link truncated URLs containing parentheses (…/Topic_(disambiguation)). Match the balanced closing paren instead of the first ) (find_matching_paren). 4. Unmatched ** emitted one literal * then re-parsed the second as italic. Emit both asterisks and advance by two. Adds regression tests for all four.
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.
Summary
Fixes #1.
slack messages senddefaults to--format markdownbut performed no conversion — Slack parses thetextfield as mrkdwn (not Markdown), so**bold**and[text](url)rendered as literal characters.This adds a dependency-free Markdown→mrkdwn converter applied on the send path.
Conversions
**bold**,__bold__*bold**italic*,_italic__italic_~~strike~~~strike~# Heading*Heading*(bold line)[text](url),<url|text>- item/* item/+ item• item1. item/1) item1. item(normalized)The
•bullet and kept-number ordered lists mirror what Slack's own composer produces (confirmed against a real posted message).Protected (passed through untouched): inline code
`…`, fenced code blocks, and existing mrkdwn spans (<@U…>mentions,<url|text>links) — so nothing gets double-encoded.--format plainis unchanged (sends verbatim, mrkdwn parsing disabled).Implementation
src/utils/mrkdwn.rs— a small byte-scanning converter (no regex/deps), handling fenced/inline code, block-level line transforms (headings, lists, blockquotes), and inline spans with UTF-8-safe scanning.src/cli/messages.rs— theMessageFormat::Markdownarm now converts before sending.Testing
🤖 Generated with pi
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.