elvish/pkg/eval/vals/index_string.go

53 lines
1.1 KiB
Go

package vals
import (
"errors"
"unicode/utf8"
)
var errIndexNotAtRuneBoundary = errors.New("index not at rune boundary")
func indexString(s string, index any) (string, error) {
i, j, err := convertStringIndex(index, s)
if err != nil {
return "", err
}
return s[i:j], nil
}
func convertStringIndex(rawIndex any, s string) (int, int, error) {
index, err := ConvertListIndex(rawIndex, len(s))
if err != nil {
return 0, 0, err
}
if index.Slice {
lower, upper := index.Lower, index.Upper
if startsWithRuneBoundary(s[lower:]) && endsWithRuneBoundary(s[:upper]) {
return lower, upper, nil
}
return 0, 0, errIndexNotAtRuneBoundary
}
// Not slice
r, size := utf8.DecodeRuneInString(s[index.Lower:])
if r == utf8.RuneError {
return 0, 0, errIndexNotAtRuneBoundary
}
return index.Lower, index.Lower + size, nil
}
func startsWithRuneBoundary(s string) bool {
if s == "" {
return true
}
r, _ := utf8.DecodeRuneInString(s)
return r != utf8.RuneError
}
func endsWithRuneBoundary(s string) bool {
if s == "" {
return true
}
r, _ := utf8.DecodeLastRuneInString(s)
return r != utf8.RuneError
}