mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
perf: Replaced a bunch of string array concats with strings.Builders.
This commit is contained in:
+7
-10
@@ -21,37 +21,34 @@ ALERT_EMOJIS: map[string]string = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inject_alerts :: proc(html: string) -> string {
|
inject_alerts :: proc(html: string) -> string {
|
||||||
parts: [dynamic]string
|
sb := strings.builder_make()
|
||||||
defer delete(parts)
|
defer strings.builder_destroy(&sb)
|
||||||
|
|
||||||
remaining := html
|
remaining := html
|
||||||
|
|
||||||
for {
|
for {
|
||||||
bq_start := strings.index(remaining, "<blockquote>")
|
bq_start := strings.index(remaining, "<blockquote>")
|
||||||
if bq_start < 0 {
|
if bq_start < 0 {
|
||||||
append(&parts, remaining)
|
strings.write_string(&sb, remaining)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
bq_close := strings.index(remaining, "</blockquote>")
|
bq_close := strings.index(remaining, "</blockquote>")
|
||||||
if bq_close < 0 {
|
if bq_close < 0 {
|
||||||
append(&parts, remaining)
|
strings.write_string(&sb, remaining)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
bq_end := bq_close + len("</blockquote>")
|
bq_end := bq_close + len("</blockquote>")
|
||||||
bq := remaining[bq_start:bq_end]
|
bq := remaining[bq_start:bq_end]
|
||||||
|
|
||||||
// Append text before this blockquote
|
strings.write_string(&sb, remaining[:bq_start])
|
||||||
append(&parts, remaining[:bq_start])
|
strings.write_string(&sb, transform_alert(bq))
|
||||||
|
|
||||||
// Transform if it's an alert, otherwise keep as-is
|
|
||||||
append(&parts, transform_alert(bq))
|
|
||||||
|
|
||||||
remaining = remaining[bq_end:]
|
remaining = remaining[bq_end:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.join(parts[:], "")
|
return strings.to_string(sb)
|
||||||
}
|
}
|
||||||
|
|
||||||
transform_alert :: proc(bq: string) -> string {
|
transform_alert :: proc(bq: string) -> string {
|
||||||
|
|||||||
+9
-13
@@ -384,30 +384,27 @@ expand_emoji :: proc(text: string) -> string {
|
|||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
parts: [dynamic]string
|
sb := strings.builder_make()
|
||||||
defer delete(parts)
|
defer strings.builder_destroy(&sb)
|
||||||
|
|
||||||
remaining := text
|
remaining := text
|
||||||
|
|
||||||
for {
|
for {
|
||||||
colon := strings.index(remaining, ":")
|
colon := strings.index(remaining, ":")
|
||||||
if colon < 0 {
|
if colon < 0 {
|
||||||
append(&parts, remaining)
|
strings.write_string(&sb, remaining)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the closing colon
|
|
||||||
after := remaining[colon + 1:]
|
after := remaining[colon + 1:]
|
||||||
end := strings.index(after, ":")
|
end := strings.index(after, ":")
|
||||||
if end < 0 {
|
if end < 0 {
|
||||||
append(&parts, remaining)
|
strings.write_string(&sb, remaining)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
shortcode := remaining[colon + 1 : colon + 1 + end]
|
shortcode := remaining[colon + 1 : colon + 1 + end]
|
||||||
|
|
||||||
// Validate: shortcode must be all lowercase letters, digits, or underscores
|
|
||||||
// and must not contain whitespace
|
|
||||||
valid := true
|
valid := true
|
||||||
for c in shortcode {
|
for c in shortcode {
|
||||||
if !(c >= 'a' && c <= 'z') && !(c >= '0' && c <= '9') && c != '_' && c != '+' && c != '-' {
|
if !(c >= 'a' && c <= 'z') && !(c >= '0' && c <= '9') && c != '_' && c != '+' && c != '-' {
|
||||||
@@ -416,23 +413,22 @@ expand_emoji :: proc(text: string) -> string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !valid || len(shortcode) == 0 {
|
if !valid || len(shortcode) == 0 {
|
||||||
append(&parts, remaining[:colon + 1])
|
strings.write_string(&sb, remaining[:colon + 1])
|
||||||
remaining = remaining[colon + 1:]
|
remaining = remaining[colon + 1:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
emoji, found := EMOJIS[shortcode]
|
emoji, found := EMOJIS[shortcode]
|
||||||
if !found {
|
if !found {
|
||||||
append(&parts, remaining[:colon + 1])
|
strings.write_string(&sb, remaining[:colon + 1])
|
||||||
remaining = remaining[colon + 1:]
|
remaining = remaining[colon + 1:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace :shortcode: with emoji
|
strings.write_string(&sb, remaining[:colon])
|
||||||
append(&parts, remaining[:colon])
|
strings.write_string(&sb, emoji)
|
||||||
append(&parts, emoji)
|
|
||||||
remaining = remaining[colon + 1 + end + 1:]
|
remaining = remaining[colon + 1 + end + 1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.join(parts[:], "")
|
return strings.to_string(sb)
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-15
@@ -20,11 +20,11 @@ strip_definitions :: proc(
|
|||||||
clean_body: string,
|
clean_body: string,
|
||||||
sn_defs, mn_defs: map[string]string,
|
sn_defs, mn_defs: map[string]string,
|
||||||
) {
|
) {
|
||||||
// TODO: Should this be temp allocated?
|
|
||||||
lines := strings.split(body, "\n")
|
lines := strings.split(body, "\n")
|
||||||
defer delete(lines)
|
defer delete(lines)
|
||||||
output_lines: [dynamic]string
|
|
||||||
defer delete(output_lines)
|
out_sb := strings.builder_make()
|
||||||
|
defer strings.builder_destroy(&out_sb)
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(lines) {
|
for i < len(lines) {
|
||||||
@@ -32,48 +32,51 @@ strip_definitions :: proc(
|
|||||||
|
|
||||||
id, def_text, kind, is_def := parse_def_line(line)
|
id, def_text, kind, is_def := parse_def_line(line)
|
||||||
if !is_def {
|
if !is_def {
|
||||||
append(&output_lines, line)
|
if strings.builder_len(out_sb) > 0 {
|
||||||
|
strings.write_string(&out_sb, "\n")
|
||||||
|
}
|
||||||
|
strings.write_string(&out_sb, line)
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect definition text (initial line + multi-line continuations)
|
def_sb := strings.builder_make()
|
||||||
def_parts: [dynamic]string
|
|
||||||
if def_text != "" {
|
if def_text != "" {
|
||||||
append(&def_parts, def_text)
|
strings.write_string(&def_sb, def_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
for i < len(lines) {
|
for i < len(lines) {
|
||||||
next := lines[i]
|
next := lines[i]
|
||||||
// Stop at blank lines
|
|
||||||
if len(next) == 0 {
|
if len(next) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Stop at new note definitions
|
|
||||||
_, _, _, is_new_def := parse_def_line(next)
|
_, _, _, is_new_def := parse_def_line(next)
|
||||||
if is_new_def {
|
if is_new_def {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Include as continuation (trim indented lines)
|
if strings.builder_len(def_sb) > 0 {
|
||||||
|
strings.write_string(&def_sb, "\n")
|
||||||
|
}
|
||||||
if is_indented(next) {
|
if is_indented(next) {
|
||||||
append(&def_parts, strings.trim_left(next, " \t"))
|
strings.write_string(&def_sb, strings.trim_left(next, " \t"))
|
||||||
} else {
|
} else {
|
||||||
append(&def_parts, next)
|
strings.write_string(&def_sb, next)
|
||||||
}
|
}
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
joined := strings.join(def_parts[:], "\n")
|
joined := strings.clone(strings.to_string(def_sb))
|
||||||
|
strings.builder_destroy(&def_sb)
|
||||||
|
|
||||||
if kind == .Marginnote {
|
if kind == .Marginnote {
|
||||||
mn_defs[id] = joined
|
mn_defs[id] = joined
|
||||||
} else {
|
} else {
|
||||||
sn_defs[id] = joined
|
sn_defs[id] = joined
|
||||||
}
|
}
|
||||||
delete(def_parts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clean_body = strings.join(output_lines[:], "\n")
|
clean_body = strings.clone(strings.to_string(out_sb))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-28
@@ -244,37 +244,39 @@ capture_name_to_css :: proc(name: string) -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
escape_html :: proc(s: string) -> string {
|
escape_html :: proc(s: string) -> string {
|
||||||
parts: [dynamic]string
|
sb := strings.builder_make()
|
||||||
defer delete(parts)
|
defer strings.builder_destroy(&sb)
|
||||||
|
|
||||||
start := 0
|
start := 0
|
||||||
for i in 0..<len(s) {
|
for i in 0..<len(s) {
|
||||||
switch s[i] {
|
switch s[i] {
|
||||||
case '&':
|
case '&':
|
||||||
if i > start do append(&parts, s[start:i])
|
if i > start do strings.write_string(&sb, s[start:i])
|
||||||
append(&parts, "&")
|
strings.write_string(&sb, "&")
|
||||||
start = i + 1
|
start = i + 1
|
||||||
case '<':
|
case '<':
|
||||||
if i > start do append(&parts, s[start:i])
|
if i > start do strings.write_string(&sb, s[start:i])
|
||||||
append(&parts, "<")
|
strings.write_string(&sb, "<")
|
||||||
start = i + 1
|
start = i + 1
|
||||||
case '>':
|
case '>':
|
||||||
if i > start do append(&parts, s[start:i])
|
if i > start do strings.write_string(&sb, s[start:i])
|
||||||
append(&parts, ">")
|
strings.write_string(&sb, ">")
|
||||||
start = i + 1
|
start = i + 1
|
||||||
case '"':
|
case '"':
|
||||||
if i > start do append(&parts, s[start:i])
|
if i > start do strings.write_string(&sb, s[start:i])
|
||||||
append(&parts, """)
|
strings.write_string(&sb, """)
|
||||||
start = i + 1
|
start = i + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if start < len(s) do append(&parts, s[start:])
|
if start == 0 do return s
|
||||||
if len(parts) == 0 do return s
|
if start < len(s) do strings.write_string(&sb, s[start:])
|
||||||
return strings.join(parts[:], "")
|
return strings.to_string(sb)
|
||||||
}
|
}
|
||||||
|
|
||||||
unescape_html :: proc(s: string) -> string {
|
unescape_html :: proc(s: string) -> string {
|
||||||
parts: [dynamic]string
|
sb := strings.builder_make()
|
||||||
defer delete(parts)
|
defer strings.builder_destroy(&sb)
|
||||||
|
|
||||||
start := 0
|
start := 0
|
||||||
for i in 0..<len(s) {
|
for i in 0..<len(s) {
|
||||||
if s[i] != '&' do continue
|
if s[i] != '&' do continue
|
||||||
@@ -290,13 +292,13 @@ unescape_html :: proc(s: string) -> string {
|
|||||||
case "'", "'": replacement = "'"
|
case "'", "'": replacement = "'"
|
||||||
case: continue
|
case: continue
|
||||||
}
|
}
|
||||||
if i > start do append(&parts, s[start:i])
|
if i > start do strings.write_string(&sb, s[start:i])
|
||||||
append(&parts, replacement)
|
strings.write_string(&sb, replacement)
|
||||||
start = i + semi + 1
|
start = i + semi + 1
|
||||||
}
|
}
|
||||||
if start < len(s) do append(&parts, s[start:])
|
if start == 0 do return s
|
||||||
if len(parts) == 0 do return s
|
if start < len(s) do strings.write_string(&sb, s[start:])
|
||||||
return strings.join(parts[:], "")
|
return strings.to_string(sb)
|
||||||
}
|
}
|
||||||
|
|
||||||
highlight_block :: proc(code: string, lang: string, file_path: string) -> string {
|
highlight_block :: proc(code: string, lang: string, file_path: string) -> string {
|
||||||
@@ -416,19 +418,22 @@ highlight_code :: proc(html: string, file_path: string) -> string {
|
|||||||
PREFIX :: `<pre><code class="language-`
|
PREFIX :: `<pre><code class="language-`
|
||||||
CODE_END :: `</code></pre>`
|
CODE_END :: `</code></pre>`
|
||||||
|
|
||||||
parts: [dynamic]string
|
sb := strings.builder_make()
|
||||||
defer delete(parts)
|
defer strings.builder_destroy(&sb)
|
||||||
|
|
||||||
pos := 0
|
pos := 0
|
||||||
|
found := false
|
||||||
|
|
||||||
for {
|
for {
|
||||||
rel := strings.index(html[pos:], PREFIX)
|
rel := strings.index(html[pos:], PREFIX)
|
||||||
if rel < 0 {
|
if rel < 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
found = true
|
||||||
idx := pos + rel
|
idx := pos + rel
|
||||||
|
|
||||||
if idx > pos {
|
if idx > pos {
|
||||||
append(&parts, html[pos:idx])
|
strings.write_string(&sb, html[pos:idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
lang_start := idx + len(PREFIX)
|
lang_start := idx + len(PREFIX)
|
||||||
@@ -455,17 +460,17 @@ highlight_code :: proc(html: string, file_path: string) -> string {
|
|||||||
|
|
||||||
code := html[code_start:end_idx]
|
code := html[code_start:end_idx]
|
||||||
highlighted := highlight_block(code, lang, file_path)
|
highlighted := highlight_block(code, lang, file_path)
|
||||||
append(&parts, fmt.tprintf(`<pre><code class="language-%s">%s</code></pre>`, lang, highlighted))
|
strings.write_string(&sb, fmt.tprintf(`<pre><code class="language-%s">%s</code></pre>`, lang, highlighted))
|
||||||
|
|
||||||
pos = end_idx + len(CODE_END)
|
pos = end_idx + len(CODE_END)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pos < len(html) {
|
if pos < len(html) && found {
|
||||||
append(&parts, html[pos:])
|
strings.write_string(&sb, html[pos:])
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(parts) == 0 {
|
if !found {
|
||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
return strings.join(parts[:], "")
|
return strings.to_string(sb)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-8
@@ -70,14 +70,15 @@ Posts_Data :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
strip_html_tags :: proc(s: string) -> string {
|
strip_html_tags :: proc(s: string) -> string {
|
||||||
parts: [dynamic]string
|
sb := strings.builder_make()
|
||||||
defer delete(parts)
|
defer strings.builder_destroy(&sb)
|
||||||
|
|
||||||
in_tag := false
|
in_tag := false
|
||||||
start := 0
|
start := 0
|
||||||
for i in 0 ..< len(s) {
|
for i in 0 ..< len(s) {
|
||||||
if s[i] == '<' && !in_tag {
|
if s[i] == '<' && !in_tag {
|
||||||
if i > start {
|
if i > start {
|
||||||
append(&parts, s[start:i])
|
strings.write_string(&sb, s[start:i])
|
||||||
}
|
}
|
||||||
in_tag = true
|
in_tag = true
|
||||||
} else if s[i] == '>' && in_tag {
|
} else if s[i] == '>' && in_tag {
|
||||||
@@ -85,13 +86,13 @@ strip_html_tags :: proc(s: string) -> string {
|
|||||||
start = i + 1
|
start = i + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !in_tag && start < len(s) {
|
if start == 0 {
|
||||||
append(&parts, s[start:])
|
|
||||||
}
|
|
||||||
if len(parts) == 0 {
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
return strings.join(parts[:], "")
|
if !in_tag && start < len(s) {
|
||||||
|
strings.write_string(&sb, s[start:])
|
||||||
|
}
|
||||||
|
return strings.to_string(sb)
|
||||||
}
|
}
|
||||||
|
|
||||||
og_type :: proc(is_article: bool) -> string {
|
og_type :: proc(is_article: bool) -> string {
|
||||||
|
|||||||
+14
-10
@@ -5,10 +5,12 @@ import "core:strings"
|
|||||||
wrap_sections :: proc(html: string) -> string {
|
wrap_sections :: proc(html: string) -> string {
|
||||||
H2 :: "<h2"
|
H2 :: "<h2"
|
||||||
|
|
||||||
parts: [dynamic]string
|
sb := strings.builder_make()
|
||||||
defer delete(parts)
|
defer strings.builder_destroy(&sb)
|
||||||
|
|
||||||
pos := 0
|
pos := 0
|
||||||
search_pos := 0
|
search_pos := 0
|
||||||
|
found := false
|
||||||
|
|
||||||
for {
|
for {
|
||||||
rel := strings.index(html[search_pos:], H2)
|
rel := strings.index(html[search_pos:], H2)
|
||||||
@@ -16,11 +18,12 @@ wrap_sections :: proc(html: string) -> string {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
idx := search_pos + rel
|
idx := search_pos + rel
|
||||||
|
found = true
|
||||||
|
|
||||||
if idx > pos {
|
if idx > pos {
|
||||||
append(&parts, "<section>")
|
strings.write_string(&sb, "<section>")
|
||||||
append(&parts, html[pos:idx])
|
strings.write_string(&sb, html[pos:idx])
|
||||||
append(&parts, "</section>")
|
strings.write_string(&sb, "</section>")
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = idx
|
pos = idx
|
||||||
@@ -28,13 +31,14 @@ wrap_sections :: proc(html: string) -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pos < len(html) {
|
if pos < len(html) {
|
||||||
append(&parts, "<section>")
|
strings.write_string(&sb, "<section>")
|
||||||
append(&parts, html[pos:])
|
strings.write_string(&sb, html[pos:])
|
||||||
append(&parts, "</section>")
|
strings.write_string(&sb, "</section>")
|
||||||
|
found = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(parts) == 0 {
|
if !found {
|
||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
return strings.join(parts[:], "")
|
return strings.to_string(sb)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user