feat(markdown): replace GitHub emoji shortcodes inline#617
Conversation
There was a problem hiding this comment.
rainxchzed has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (15)
WalkthroughAdds a Kotlin EmojiShortcodes utility that replaces GitHub-style :shortcode: tokens with Unicode emoji outside fenced code blocks, wires it into markdown preprocessing as Phase 15, and updates localized release notes to document the feature. ChangesEmoji Shortcode Rendering Feature
Sequence DiagramsequenceDiagram
participant User as User/Content
participant PreProcess as preprocessMarkdown()
participant Shortcodes as EmojiShortcodes.render()
participant Split as splitOutCodeRegions()
participant Replace as replaceInText()
participant Output as Rendered Markdown
User->>PreProcess: supply markdown with :rocket:
PreProcess->>Shortcodes: Phase 15: render emoji
Shortcodes->>Split: detect ``` code fences
Split->>Replace: text chunks (exclude code)
Replace->>Replace: lookup :rocket: → 🚀 via TABLE
Shortcodes->>Output: reconstructed markdown
Output->>User: returned markdown with 🚀
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/EmojiShortcodes.kt (1)
4-8: ⚡ Quick winReduce non-essential inline comments to match Kotlin file guidelines.
This file introduces many narrative section comments; keep only comments for non-obvious invariants/workarounds.
As per coding guidelines, "Do not add KDoc or inline comments unless explicitly requested; only add inline comments for non-obvious invariants, tricky concurrency, or workarounds".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/EmojiShortcodes.kt` around lines 4 - 8, The top-of-file narrative comments in EmojiShortcodes.kt are too verbose; remove or condense them so only non-obvious invariants, workarounds, or essential notes remain. Specifically, edit the header comment block above the emoji table/definitions in the EmojiShortcodes object (or top-level declarations) to delete narrative lines about selection rationale and bundle size, or convert them into a single short sentence explaining the subset decision; keep only comments that document tricky invariants or necessary behavior. Ensure no additional KDoc or inline commentary is added elsewhere in the file unless it documents a non-obvious invariant or workaround.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/EmojiShortcodes.kt`:
- Around line 361-383: The current split logic treats every triple-backtick
substring as a fence, misclassifying inline backticks; replace the
substring-based parsing with a line-oriented detector in splitOutCodeRegions so
fences are only recognized when they occur on their own (up to 3 leading spaces)
using a regex like ^\s{0,3}```.*$; iterate lines, accumulate non-fence lines
into a buffer and flush into Chunk(buffer, isCode=current) when encountering a
fence line, add the fence line itself as a Chunk(isCode=true) (preserve trailing
newlines between lines), toggle inCode on fence lines, and return the collected
List<Chunk> so emoji replacement only ignores true markdown code blocks.
In `@core/presentation/src/commonMain/composeResources/files/whatsnew/18.json`:
- Line 32: The whatsnew JSON entry string "Emoji shortcodes in README and
release notes — :rocket: now renders as 🚀, :tada: as 🎉, and ~250 others.
Common dev/status icons covered out of the box." has an inaccurate shortcode
count; update that text to reflect the implemented ~330 shortcodes (e.g.,
replace "~250 others" with "~330 others" or "around 330 others") so the entry
accurately matches the implementation.
In `@core/presentation/src/commonMain/composeResources/files/whatsnew/ja/18.json`:
- Line 32: The Japanese string "README とリリースノートで絵文字ショートコードに対応 — :rocket: は
🚀、:tada: は 🎉、合計約 250 種類。" is semantically inconsistent with the English "~250
others"; update this Japanese sentence to mirror the final English phrasing and
corrected count (e.g., replace "合計約 250 種類" with the equivalent Japanese of
"~250 others" like "その他約250種類" or with the corrected total count such as
"合計約252種類") so the locales convey the same meaning.
---
Nitpick comments:
In
`@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/EmojiShortcodes.kt`:
- Around line 4-8: The top-of-file narrative comments in EmojiShortcodes.kt are
too verbose; remove or condense them so only non-obvious invariants,
workarounds, or essential notes remain. Specifically, edit the header comment
block above the emoji table/definitions in the EmojiShortcodes object (or
top-level declarations) to delete narrative lines about selection rationale and
bundle size, or convert them into a single short sentence explaining the subset
decision; keep only comments that document tricky invariants or necessary
behavior. Ensure no additional KDoc or inline commentary is added elsewhere in
the file unless it documents a non-obvious invariant or workaround.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0d1efd48-b0c8-4ae2-8bc6-948454dc9a77
📒 Files selected for processing (15)
core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/EmojiShortcodes.ktcore/presentation/src/commonMain/composeResources/files/whatsnew/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/ar/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/bn/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/es/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/fr/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/hi/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/it/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/ja/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/ko/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/pl/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/ru/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/tr/18.jsoncore/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/18.jsonfeature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/utils/preprocessMarkdown.kt
| val fence = "```" | ||
| if (!input.contains(fence)) return listOf(Chunk(input, isCode = false)) | ||
| val out = mutableListOf<Chunk>() | ||
| var i = 0 | ||
| var inCode = false | ||
| while (i < input.length) { | ||
| val next = input.indexOf(fence, startIndex = i) | ||
| if (next < 0) { | ||
| out += Chunk(input.substring(i), isCode = inCode) | ||
| break | ||
| } | ||
| // Take everything up to and including the fence into the | ||
| // current region — the fence itself is part of the code | ||
| // block when we're transitioning out, so always include | ||
| // 3 chars in the "code" side. | ||
| if (inCode) { | ||
| out += Chunk(input.substring(i, next + fence.length), isCode = true) | ||
| } else { | ||
| out += Chunk(input.substring(i, next), isCode = false) | ||
| out += Chunk(fence, isCode = true) | ||
| } | ||
| i = next + fence.length | ||
| inCode = !inCode |
There was a problem hiding this comment.
Fence parsing toggles on any ``` occurrence, not actual markdown fence lines.
Current logic treats every triple-backtick substring as a fence delimiter. That can mis-split regions when backticks appear in normal text/content, causing incorrect emoji replacement scope.
Proposed direction (line-based fence detection)
- private fun splitOutCodeRegions(input: String): List<Chunk> {
- val fence = "```"
- if (!input.contains(fence)) return listOf(Chunk(input, isCode = false))
- val out = mutableListOf<Chunk>()
- var i = 0
- var inCode = false
- while (i < input.length) {
- val next = input.indexOf(fence, startIndex = i)
- if (next < 0) {
- out += Chunk(input.substring(i), isCode = inCode)
- break
- }
- if (inCode) {
- out += Chunk(input.substring(i, next + fence.length), isCode = true)
- } else {
- out += Chunk(input.substring(i, next), isCode = false)
- out += Chunk(fence, isCode = true)
- }
- i = next + fence.length
- inCode = !inCode
- }
- return out
- }
+ private fun splitOutCodeRegions(input: String): List<Chunk> {
+ val lines = input.split('\n')
+ if (lines.none { it.matches(Regex("""^\s{0,3}```.*$""")) }) {
+ return listOf(Chunk(input, isCode = false))
+ }
+ val out = mutableListOf<Chunk>()
+ val buffer = StringBuilder()
+ var inCode = false
+
+ fun flush() {
+ if (buffer.isNotEmpty()) {
+ out += Chunk(buffer.toString(), isCode = inCode)
+ buffer.clear()
+ }
+ }
+
+ lines.forEachIndexed { idx, line ->
+ val isFenceLine = line.matches(Regex("""^\s{0,3}```.*$"""))
+ if (isFenceLine) {
+ flush()
+ out += Chunk(line + if (idx != lines.lastIndex) "\n" else "", isCode = true)
+ inCode = !inCode
+ } else {
+ buffer.append(line)
+ if (idx != lines.lastIndex) buffer.append('\n')
+ }
+ }
+ flush()
+ return out
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| val fence = "```" | |
| if (!input.contains(fence)) return listOf(Chunk(input, isCode = false)) | |
| val out = mutableListOf<Chunk>() | |
| var i = 0 | |
| var inCode = false | |
| while (i < input.length) { | |
| val next = input.indexOf(fence, startIndex = i) | |
| if (next < 0) { | |
| out += Chunk(input.substring(i), isCode = inCode) | |
| break | |
| } | |
| // Take everything up to and including the fence into the | |
| // current region — the fence itself is part of the code | |
| // block when we're transitioning out, so always include | |
| // 3 chars in the "code" side. | |
| if (inCode) { | |
| out += Chunk(input.substring(i, next + fence.length), isCode = true) | |
| } else { | |
| out += Chunk(input.substring(i, next), isCode = false) | |
| out += Chunk(fence, isCode = true) | |
| } | |
| i = next + fence.length | |
| inCode = !inCode | |
| private fun splitOutCodeRegions(input: String): List<Chunk> { | |
| val lines = input.split('\n') | |
| if (lines.none { it.matches(Regex("""^\s{0,3} |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/EmojiShortcodes.kt`
around lines 361 - 383, The current split logic treats every triple-backtick
substring as a fence, misclassifying inline backticks; replace the
substring-based parsing with a line-oriented detector in splitOutCodeRegions so
fences are only recognized when they occur on their own (up to 3 leading spaces)
using a regex like ^\s{0,3}```.*$; iterate lines, accumulate non-fence lines
into a buffer and flush into Chunk(buffer, isCode=current) when encountering a
fence line, add the fence line itself as a Chunk(isCode=true) (preserve trailing
newlines between lines), toggle inCode on fence lines, and return the collected
List<Chunk> so emoji replacement only ignores true markdown code blocks.
| "Manually linking apps — sorted by installer source (F-Droid / Obtainium first, Play Store and system updates last) with a chip showing each app's source.", | ||
| "Manual link now suggests matching GitHub repos automatically — pick an app, get ranked candidates, tap to link. Manual URL entry still available." | ||
| "Manual link now suggests matching GitHub repos automatically — pick an app, get ranked candidates, tap to link. Manual URL entry still available.", | ||
| "Emoji shortcodes in README and release notes — :rocket: now renders as 🚀, :tada: as 🎉, and ~250 others. Common dev/status icons covered out of the box." |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Count the actual number of emoji shortcodes in the implementation
# Search for the shortcode map definition in EmojiShortcodes
ast-grep --pattern 'mapOf(
$$$
)' | rg -c ':\w+:' || echo "Pattern not found, trying alternative search"
# Alternative: search for shortcode entries in the file
rg -o '"\w+"\s+to\s+".' core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/util/EmojiShortcodes.kt | wc -lRepository: OpenHub-Store/GitHub-Store
Length of output: 78
Update emoji shortcode count to reflect actual implementation.
The JSON file states "~250 others" but verification reveals the implementation contains approximately 330 shortcodes total, not ~250. Update the text to accurately reflect this count.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/presentation/src/commonMain/composeResources/files/whatsnew/18.json` at
line 32, The whatsnew JSON entry string "Emoji shortcodes in README and release
notes — :rocket: now renders as 🚀, :tada: as 🎉, and ~250 others. Common
dev/status icons covered out of the box." has an inaccurate shortcode count;
update that text to reflect the implemented ~330 shortcodes (e.g., replace "~250
others" with "~330 others" or "around 330 others") so the entry accurately
matches the implementation.
| "手動リンク — インストーラ別に並び替え(F-Droid / Obtainium が先、Play ストアやシステム更新は最後)し、各アプリの入手元をチップで表示。", | ||
| "手動リンクが一致する GitHub リポを自動提案 — アプリを選ぶとランク付き候補が出る。タップでリンク。手動 URL 入力も引き続き利用可能。" | ||
| "手動リンクが一致する GitHub リポを自動提案 — アプリを選ぶとランク付き候補が出る。タップでリンク。手動 URL 入力も引き続き利用可能。", | ||
| "README とリリースノートで絵文字ショートコードに対応 — :rocket: は 🚀、:tada: は 🎉、合計約 250 種類。" |
There was a problem hiding this comment.
Semantic discrepancy with English version.
The Japanese text says "合計約 250 種類" (approximately 250 total types), but the English version says "~250 others" (implying 252+ total including :rocket: and :tada:). This creates an inconsistency across locales.
If the English version is corrected per the count verification issue, ensure the Japanese translation aligns with the final phrasing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/presentation/src/commonMain/composeResources/files/whatsnew/ja/18.json`
at line 32, The Japanese string "README とリリースノートで絵文字ショートコードに対応 — :rocket: は
🚀、:tada: は 🎉、合計約 250 種類。" is semantically inconsistent with the English "~250
others"; update this Japanese sentence to mirror the final English phrasing and
corrected count (e.g., replace "合計約 250 種類" with the equivalent Japanese of
"~250 others" like "その他約250種類" or with the corrected total count such as
"合計約252種類") so the locales convey the same meaning.
187086f to
aec46b3
Compare
There was a problem hiding this comment.
rainxchzed has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.
`:rocket:` → 🚀, `:tada:` → 🎉, ~250 common shortcodes total. Preprocessor pass runs after HTML normalization and skips fenced code blocks so legitimate `:foo:` syntax in code isn't clobbered. Unknown shortcodes pass through as literal text.
Test plan
Summary by CodeRabbit
New Features
:rocket:→ 🚀,:tada:→ 🎉, plus ~250 others), preserving code blocks.Documentation