Skip to content

Commit

Permalink
Support basic Markdown formatting (#520)
Browse files Browse the repository at this point in the history
* Add #markdown utility

* Chain markdown formatting and test nested tokens

* Support markdown's *italic*
  • Loading branch information
nbgoodall authored Jul 7, 2024
1 parent 1e14946 commit dfcf059
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### 2.3.1 (Next)

* [#516](https://github.com/slack-ruby/slack-ruby-client/pull/516): Add support for Ruby 3.3 - [@olleolleolle](https://github.com/olleolleolle).
* [#520](https://github.com/slack-ruby/slack-ruby-client/pull/520): Support basic markdown formatting - [@nbgoodall](https://github.com/nbgoodall).
* Your contribution here.

### 2.3.0 (2024/01/31)
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ A Ruby client for the Slack [Web](https://api.slack.com/web), [RealTime Messagin
- [Channel ID formatting](#channel-id-formatting)
- [User ID formatting](#user-id-formatting)
- [URL formatting](#url-formatting)
- [Markdown formatting](#markdown-formatting)
- [Parsing Messages](#parsing-messages)
- [Unescaping message content](#unescaping-message-content)
- [Escaping message content](#escaping-message-content)
Expand Down Expand Up @@ -657,6 +658,30 @@ Slack::Messages::Formatting.url_link(text, url)
# => "<https://media.giphy.com/media/AcfTF7tyikWyroP0x7/giphy.gif|party time>"
```

##### Markdown formatting

Slack uses a mishmash of regular markdown formatting with its own syntax. Some features like headings aren't supported and will be left as-is, but others like bold, strikethrough, and links are converted.

```ruby
text = """
## A heading
**Bold text**
~~Strikethrough text~~
_Italic text_
[A link](https://example.com)
`code`
"""
Slack::Messages::Formatting.markdown(text)
# => """
# ## A heading
# *Bold text*
# ~Strikethrough text~
# _Italic text_
# <https://example.com|A link>
# `code`
# """
```

#### Parsing Messages

`Slack::Messages::Formatting` also provides ways to escape or unescape messages. This comes handy, for example, you want to treat all input to a real time bot as plain text.
Expand Down
13 changes: 13 additions & 0 deletions lib/slack/messages/formatting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ def user_link(user_id)
def url_link(text, url)
"<#{url}|#{text}>"
end

#
# Converts text from basic markdown into Slack's mishmash
# @see https://api.slack.com/reference/surfaces/formatting#basic-formatting
#
def markdown(text)
text
.gsub(/(?<!\*)\*([^*]+)\*(?!\*)/, '_\1_') # italic
.gsub(/\*\*\*(.*?)\*\*\*/, '*_\1_*') # bold & italic
.gsub(/\*\*(.*?)\*\*/, '*\1*') # bold
.gsub(/~~(.*?)~~/, '~\1~') # strikethrough
.gsub(/\[(.*?)\]\((.*?)\)/, '<\2|\1>') # links
end
end
end
end
Expand Down
32 changes: 32 additions & 0 deletions spec/slack/messages/formatting_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,36 @@
expect(formatting.url_link(text, url)).to eq "<#{url}|#{text}>"
end
end

context '#markdown' do
it 'formats markdown bold' do
expect(formatting.markdown('**Le bold**')).to eq '*Le bold*'
end

it 'formats markdown italic' do
expect(formatting.markdown("*L'italic*")).to eq "_L'italic_"
end

it 'formats markdown bold and italic' do
expect(formatting.markdown('***Le bold italic***')).to eq '*_Le bold italic_*'
end

it 'formats markdown strikethrough' do
expect(formatting.markdown('~~Le strikethrough~~')).to eq '~Le strikethrough~'
end

it 'formats markdown links' do
expect(formatting.markdown('[Le link](https://theuselessweb.site)')).to eq '<https://theuselessweb.site|Le link>'
end

it 'formats nested markdown' do
expect(formatting.markdown('**[Le **bold and ~~struckout with *italic*~~** link](https://theuselessweb.site)**')).to(
eq '*<https://theuselessweb.site|Le *bold and ~struckout with _italic_~* link>*'
)
end

it "doesn't format other markdown" do
expect(formatting.markdown('## A heading\n_Italics_\n`code`')).to eq '## A heading\n_Italics_\n`code`'
end
end
end

0 comments on commit dfcf059

Please sign in to comment.