config-lsp/server/utils/strings.go
2024-10-12 15:23:43 +02:00

143 lines
2.8 KiB
Go

package utils
import (
"regexp"
"strings"
)
var trimIndexPattern = regexp.MustCompile(`^\s*(.+?)\s*$`)
func GetTrimIndex(s string) []int {
indexes := trimIndexPattern.FindStringSubmatchIndex(s)
if indexes == nil {
return nil
}
return indexes[2:4]
}
func SplitIntoLines(s string) []string {
return regexp.MustCompile("\r?\n").Split(s, -1)
}
func FindPreviousCharacter(line string, character string, startIndex int) (int, bool) {
for index := startIndex; index >= 0; index-- {
if string(line[index]) == character {
return index, true
}
}
return 0, false
}
func FindNextCharacter(line string, character string, startIndex int) (int, bool) {
for index := startIndex; index < len(line); index++ {
if string(line[index]) == character {
return index, true
}
}
return 0, false
}
func CountCharacterOccurrences(line string, character rune) int {
count := 0
for _, c := range line {
if c == character {
count++
}
}
return count
}
var emptyRegex = regexp.MustCompile(`^\s*$`)
func IsEmpty(s string) bool {
return emptyRegex.MatchString(s)
}
func AllIndexes(s string, sub string) []int {
indexes := make([]int, 0)
current := s
for {
index := strings.Index(current, sub)
if index == -1 {
break
}
indexes = append(indexes, index)
current = current[index+1:]
}
return indexes
}
func FindFirstNonMatch(s string, substr map[rune]struct{}, startIndex int) int {
for index := startIndex; index < len(s); index++ {
if _, found := substr[rune(s[index])]; !found {
return index
}
}
return -1
}
func FindLastNonMatch(s string, substr map[rune]struct{}, startIndex int) int {
for index := startIndex; index >= 0; index-- {
if _, found := substr[rune(s[index])]; !found {
return index
}
}
return -1
}
var lineContinuationPattern = regexp.MustCompile(`\\\s*$`)
// SplitSmartlyIntoLines Split a string into lines while respecting "\" as a line continuation character
// This function is useful for parsing configuration files
// You will need to handle whitespace trimming yourself
// For example, the following input:
// ```
// key1 = value1
//
// key2 = value2 \
// value3
//
// key3 = value4
// ```
// Will be split into:
// ```go
//
// [][]string{
// []string{"key1 = value1"},
// []string{"key2 = value2 ", " value3"},
// []string{"key3 = value4"},
// }
func SplitIntoVirtualLines(input string) [][]string {
lines := make([][]string, 0, len(input))
currentLine := make([]string, 0, 1)
for _, line := range SplitIntoLines(input) {
if lineContinuationPattern.MatchString(line) {
currentLine = append(currentLine, line[:len(line)-1])
continue
}
currentLine = append(currentLine, line)
lines = append(lines, currentLine)
currentLine = make([]string, 0, 1)
}
if len(currentLine) > 0 {
lines = append(lines, currentLine)
}
return lines
}