slidewalk/internal/parser/split.go
Tom 0fa66d9f48 Erweiterung und CSS
- Code bekommt größere Schrift
- In einer Datei können neue Slides erstellt werden
2026-07-16 22:46:03 +02:00

92 lines
2.5 KiB
Go

package parser
import "bytes"
// slideBreakMarker is a line that, on its own, forces a new slide within a
// single source file, even though the surrounding content stays in one
// file (and shares its frontmatter).
var slideBreakMarker = []byte("<!-- new slide -->")
// splitSlideBreaks splits body into one or more parts at lines consisting
// solely of slideBreakMarker. Matches inside fenced code blocks (``` or
// ~~~) are ignored, so a marker shown as example text isn't mistaken for an
// actual break. If no marker is found, it returns body unchanged as the
// only part.
func splitSlideBreaks(body []byte) [][]byte {
lines := bytes.Split(body, []byte("\n"))
var parts [][]byte
var current [][]byte
var fence fenceState
for _, line := range lines {
trimmed := bytes.TrimSpace(line)
if !fence.active && bytes.Equal(trimmed, slideBreakMarker) {
parts = append(parts, bytes.TrimSpace(bytes.Join(current, []byte("\n"))))
current = nil
continue
}
fence.toggle(trimmed)
current = append(current, line)
}
parts = append(parts, bytes.TrimSpace(bytes.Join(current, []byte("\n"))))
if len(parts) == 1 {
return [][]byte{body}
}
nonEmpty := parts[:0]
for _, p := range parts {
if len(p) > 0 {
nonEmpty = append(nonEmpty, p)
}
}
return nonEmpty
}
// fenceState tracks whether the line currently being scanned lies inside a
// fenced code block, so a slide-break marker appearing as example text
// inside a fence isn't treated as an actual split point.
type fenceState struct {
active bool
char byte
count int
}
// toggle updates the fence state for one already-trimmed line.
func (f *fenceState) toggle(trimmed []byte) {
ch, count, ok := parseFenceLine(trimmed)
if !ok {
return
}
switch {
case !f.active:
f.active, f.char, f.count = true, ch, count
case ch == f.char && count >= f.count:
f.active = false
}
}
// parseFenceLine reports whether trimmed is a fenced-code-block delimiter
// line (a run of three or more backticks or tildes), returning the fence
// character and run length.
func parseFenceLine(trimmed []byte) (ch byte, count int, ok bool) {
if len(trimmed) < 3 {
return 0, 0, false
}
ch = trimmed[0]
if ch != '`' && ch != '~' {
return 0, 0, false
}
for count < len(trimmed) && trimmed[count] == ch {
count++
}
if count < 3 {
return 0, 0, false
}
// A backtick fence's info string cannot itself contain a backtick.
if ch == '`' && bytes.IndexByte(trimmed[count:], '`') != -1 {
return 0, 0, false
}
return ch, count, true
}