Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## [Unreleased]

### Changed
* Avoided a per-character `Seq.windowed`/`String()` allocation in `StartsWithNTimesTrimIgnoreStartWhitespace`, the active pattern used to count repeated fence characters (`` ` `` / `~`) when parsing code fences and headers. The count is now computed with `String.CompareOrdinal` over string offsets, with no intermediate substring allocations. Behavior is unchanged.

## [23.0.0-alpha.8] - 2026-09-18

### Added
Expand Down
20 changes: 16 additions & 4 deletions src/Common/StringParsing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,23 @@ module StringPosition =
if String.IsNullOrWhiteSpace(beforeStart) then
let startAndRest = text.Substring(beforeStart.Length)

// Count matches of `start` at consecutive offsets 0, 1, 2, ... in `startAndRest`
// (same semantics as the previous Seq.windowed-based implementation), without
// allocating a substring per offset.
let startNum =
Seq.windowed start.Length startAndRest
|> Seq.map (fun chars -> System.String(chars))
|> Seq.takeWhile ((=) start)
|> Seq.length
let mutable count = 0
let mutable keepGoing = true

while keepGoing do
if
count + start.Length <= startAndRest.Length
&& String.CompareOrdinal(startAndRest, count, start, 0, start.Length) = 0
then
count <- count + 1
else
keepGoing <- false

count

Some(
startNum,
Expand Down
Loading