on main help sign in
Merge pull request #351 from charmbracelet/regex-drop-compilation-in-runtime

perf: avoid regex compilation in runtime

commit98208900a77a9b8f237d7238b44ae8d1dd835041 authorRaphael Amorim <rapha850@gmail.com> dateWed 30 Jul 2025, 15:43 (1 year ago) parent979ddb53839c36
4 files changed+19−9
internal/llm/provider/anthropic.go+4−2 internal/llm/tools/view.go+2−1 internal/tui/exp/list/filterable.go+8−3 internal/tui/exp/list/filterable_group.go+5−3
internal/llm/provider/anthropic.go+4−2
@@ -21,6 +21,9 @@ import (
2121 "github.com/charmbracelet/crush/internal/message"
2222)
2323
24+// Pre-compiled regex for parsing context limit errors.
25+var contextLimitRegex = regexp.MustCompile(`input length and ` + "`max_tokens`" + ` exceed context limit: (\d+) \+ (\d+) > (\d+)`)
26+
2427type anthropicClient struct {
2528 providerOptions providerClientOptions
2629 useBedrock bool
@@ -512,8 +515,7 @@ func (a *anthropicClient) handleContextLimitError(apiErr *anthropic.Error) (int,
512515 // Parse error message like: "input length and max_tokens exceed context limit: 154978 + 50000 > 200000"
513516 errorMsg := apiErr.Error()
514517
515− re := regexp.MustCompile("input length and `max_tokens` exceed context limit: (\\d+) \\+ (\\d+) > (\\d+)")
516− matches := re.FindStringSubmatch(errorMsg)
518+ matches := contextLimitRegex.FindStringSubmatch(errorMsg)
517519
518520 if len(matches) != 4 {
519521 return 0, false
internal/llm/tools/view.go+2−1
@@ -306,7 +306,8 @@ func readTextFile(filePath string, offset, limit int) (string, int, error) {
306306 }
307307 }
308308
309− var lines []string
309+ // Pre-allocate slice with expected capacity
310+ lines := make([]string, 0, limit)
310311 lineCount = offset
311312
312313 for scanner.Scan() && len(lines) < limit {
internal/tui/exp/list/filterable.go+8−3
@@ -15,6 +15,13 @@ import (
1515 "github.com/sahilm/fuzzy"
1616)
1717
18+var (
19+ // Pre-compiled regex for checking if a string contains alphabetic characters.
20+ alphaRegex = regexp.MustCompile(`[a-zA-Z]`)
21+ // Pre-compiled regex for checking if a string is alphanumeric.
22+ alphanumericRegex = regexp.MustCompile(`^[a-zA-Z0-9]*$`)
23+)
24+
1825type FilterableItem interface {
1926 Item
2027 FilterValue() string
@@ -165,8 +172,6 @@ func (f *filterableList[T]) View() string {
165172
166173// removes bindings that are used for search
167174func (f *filterableList[T]) updateKeyMaps() {
168− alphanumeric := regexp.MustCompile("^[a-zA-Z0-9]*$")
169−
170175 removeLettersAndNumbers := func(bindings []string) []string {
171176 var keep []string
172177 for _, b := range bindings {
@@ -177,7 +182,7 @@ func (f *filterableList[T]) updateKeyMaps() {
177182 if b == " " {
178183 continue
179184 }
180− m := alphanumeric.MatchString(b)
185+ m := alphanumericRegex.MatchString(b)
181186 if !m {
182187 keep = append(keep, b)
183188 }
internal/tui/exp/list/filterable_group.go+5−3
@@ -15,6 +15,10 @@ import (
1515 "github.com/sahilm/fuzzy"
1616)
1717
18+// Pre-compiled regex for checking if a string is alphanumeric.
19+// Note: This is duplicated from filterable.go to avoid circular dependencies.
20+var alphanumericRegexGroup = regexp.MustCompile(`^[a-zA-Z0-9]*$`)
21+
1822type FilterableGroupList[T FilterableItem] interface {
1923 GroupedList[T]
2024 Cursor() *tea.Cursor
@@ -114,8 +118,6 @@ func (f *filterableGroupList[T]) View() string {
114118
115119// removes bindings that are used for search
116120func (f *filterableGroupList[T]) updateKeyMaps() {
117− alphanumeric := regexp.MustCompile("^[a-zA-Z0-9]*$")
118−
119121 removeLettersAndNumbers := func(bindings []string) []string {
120122 var keep []string
121123 for _, b := range bindings {
@@ -126,7 +128,7 @@ func (f *filterableGroupList[T]) updateKeyMaps() {
126128 if b == " " {
127129 continue
128130 }
129− m := alphanumeric.MatchString(b)
131+ m := alphanumericRegexGroup.MatchString(b)
130132 if !m {
131133 keep = append(keep, b)
132134 }