github.com/elves/elvish@v0.15.0/pkg/eval/vals/index_string.go (about) 1 package vals 2 3 import ( 4 "errors" 5 "unicode/utf8" 6 ) 7 8 var errIndexNotAtRuneBoundary = errors.New("index not at rune boundary") 9 10 func indexString(s string, index interface{}) (string, error) { 11 i, j, err := convertStringIndex(index, s) 12 if err != nil { 13 return "", err 14 } 15 return s[i:j], nil 16 } 17 18 func convertStringIndex(rawIndex interface{}, s string) (int, int, error) { 19 index, err := ConvertListIndex(rawIndex, len(s)) 20 if err != nil { 21 return 0, 0, err 22 } 23 if index.Slice { 24 lower, upper := index.Lower, index.Upper 25 if startsWithRuneBoundary(s[lower:]) && endsWithRuneBoundary(s[:upper]) { 26 return lower, upper, nil 27 } 28 return 0, 0, errIndexNotAtRuneBoundary 29 } 30 // Not slice 31 r, size := utf8.DecodeRuneInString(s[index.Lower:]) 32 if r == utf8.RuneError { 33 return 0, 0, errIndexNotAtRuneBoundary 34 } 35 return index.Lower, index.Lower + size, nil 36 } 37 38 func startsWithRuneBoundary(s string) bool { 39 if s == "" { 40 return true 41 } 42 r, _ := utf8.DecodeRuneInString(s) 43 return r != utf8.RuneError 44 } 45 46 func endsWithRuneBoundary(s string) bool { 47 if s == "" { 48 return true 49 } 50 r, _ := utf8.DecodeLastRuneInString(s) 51 return r != utf8.RuneError 52 }