diff --git a/TODOS.md b/TODOS.md index 24e2325..8a3b384 100644 --- a/TODOS.md +++ b/TODOS.md @@ -56,7 +56,8 @@ - [ ] Review main.odin - [ ] Review minify.odin - [ ] Review `markdown/` - - [ ] Review alerts.odin + - [x] Review alerts.odin + - [x] Review alerts_test.odin - [x] Review emoji.odin - [x] Review emoji_test.odin - [ ] Review footnotes.odin @@ -69,3 +70,5 @@ - [x] Review site.odin - [ ] Review treesitter/treesitter.odin - [ ] Review vfs.odin +- [ ] Review procs + - [ ] markdown.transform_alert diff --git a/markdown/alerts.odin b/markdown/alerts.odin index 483c765..7361315 100644 --- a/markdown/alerts.odin +++ b/markdown/alerts.odin @@ -4,20 +4,12 @@ package markdown import "core:fmt" import "core:strings" -ALERT_STYLES: map[string]string = { - "note" = "border-l-blue-500 bg-blue-950/30 text-slate-300", - "tip" = "border-l-green-500 bg-green-950/30 text-slate-300", - "important" = "border-l-purple-500 bg-purple-950/30 text-slate-300", - "warning" = "border-l-yellow-500 bg-yellow-950/30 text-slate-300", - "caution" = "border-l-red-500 bg-red-950/30 text-slate-300", -} - ALERT_EMOJIS: map[string]string = { - "note" = "\xe2\x84\xb9\xef\xb8\x8f", - "tip" = "\xf0\x9f\x92\xa1", - "important" = "\xe2\x9d\x97", - "warning" = "\xe2\x9a\xa0\xef\xb8\x8f", - "caution" = "\xe2\x9d\x97", + "note" = "ℹ️", + "tip" = "💡", + "important" = "❗", + "warning" = "⚠️", + "caution" = "❗", } inject_alerts :: proc(html: string) -> string { @@ -52,54 +44,52 @@ inject_alerts :: proc(html: string) -> string { } transform_alert :: proc(bq: string) -> string { - // Skip
tag and whitespace pos := len("
") - for pos < len(bq) && (bq[pos] == '\n' || bq[pos] == '\r' || bq[pos] == ' ' || bq[pos] == '\t') { + for pos < len(bq) && + (bq[pos] == '\n' || bq[pos] == '\r' || bq[pos] == ' ' || bq[pos] == '\t') { pos += 1 } - // Check for

[! - if pos + 4 >= len(bq) || bq[pos] != '<' || bq[pos + 1] != 'p' || bq[pos + 2] != '>' || - bq[pos + 3] != '[' || bq[pos + 4] != '!' { + if pos + 4 >= len(bq) || + bq[pos] != '<' || + bq[pos + 1] != 'p' || + bq[pos + 2] != '>' || + bq[pos + 3] != '[' || + bq[pos + 4] != '!' { return bq } - // Extract alert type until ] close := strings.index(bq[pos + 5:], "]") if close < 0 { return bq } - type_raw := bq[pos + 5 : pos + 5 + close] + type_raw := bq[pos + 5:pos + 5 + close] type_lower := strings.to_lower(type_raw) - style, has_style := ALERT_STYLES[type_lower] - emoji, has_emoji := ALERT_EMOJIS[type_lower] - if !has_style || !has_emoji { + emoji, found := ALERT_EMOJIS[type_lower] + if !found { return bq } - // Position after ] after_type := pos + 5 + close + 1 - // Skip optional + or - content_start := after_type if content_start < len(bq) && (bq[content_start] == '+' || bq[content_start] == '-') { content_start += 1 } - // Skip space after marker if content_start < len(bq) && bq[content_start] == ' ' { content_start += 1 } - // Rebuild: styled blockquote + bold title paragraph + rest rest := bq[content_start:] return fmt.aprintf( - `

-

%s %s`, - style, + `

+

%s %s`, + type_lower, emoji, rest, ) } + diff --git a/markdown/alerts_test.odin b/markdown/alerts_test.odin new file mode 100644 index 0000000..11ff091 --- /dev/null +++ b/markdown/alerts_test.odin @@ -0,0 +1,104 @@ +#+feature dynamic-literals +#+test +package markdown + +import "core:testing" + +@(test) +test_alerts_render_properly :: proc(t: ^testing.T) { + testing.expect_value( + t, + inject_alerts("

\n

[!NOTE] Hello.

\n
"), + `
+

ℹ️ Hello.

+
`, + ) + + testing.expect_value( + t, + inject_alerts("
\n

[!TIP] Be smart.

\n
"), + `
+

💡 Be smart.

+
`, + ) + + testing.expect_value( + t, + inject_alerts("
\n

[!CAUTION] Danger!

\n
"), + `
+

❗ Danger!

+
`, + ) +} + +@(test) +test_non_alerts_pass_through_inject_alerts :: proc(t: ^testing.T) { + testing.expect_value( + t, + inject_alerts("
\n

Just a quote.

\n
"), + "
\n

Just a quote.

\n
", + ) + + testing.expect_value( + t, + inject_alerts("
\n

[!UNKNOWN] Nope.

\n
"), + "
\n

[!UNKNOWN] Nope.

\n
", + ) + + testing.expect_value( + t, + inject_alerts("

No blockquote here.

"), + "

No blockquote here.

", + ) + + testing.expect_value(t, inject_alerts(""), "") +} + +@(test) +test_case_insensitive_alerts_render :: proc(t: ^testing.T) { + testing.expect_value( + t, + inject_alerts("
\n

[!Note] Mixed case.

\n
"), + `
+

ℹ️ Mixed case.

+
`, + ) + + testing.expect_value( + t, + inject_alerts("
\n

[!NOTE] Upper case.

\n
"), + `
+

ℹ️ Upper case.

+
`, + ) +} + +@(test) +test_multiple_alerts_render_together :: proc(t: ^testing.T) { + testing.expect_value( + t, + inject_alerts( + "
\n

[!NOTE] First.

\n
\n
\n

[!TIP] Second.

\n
", + ), + `
+

ℹ️ First.

+
+
+

💡 Second.

+
`, + ) + + testing.expect_value( + t, + inject_alerts( + "
\n

Regular.

\n
\n
\n

[!WARNING] Alert!

\n
", + ), + `
+

Regular.

+
+
+

⚠️ Alert!

+
`, + ) +} +