github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/github.com/antonmedv/expr/file/source.go (about)

     1  package file
     2  
     3  import (
     4  	"encoding/json"
     5  	"strings"
     6  	"unicode/utf8"
     7  )
     8  
     9  type Source struct {
    10  	contents    []rune
    11  	lineOffsets []int32
    12  }
    13  
    14  func NewSource(contents string) *Source {
    15  	s := &Source{
    16  		contents: []rune(contents),
    17  	}
    18  	s.updateOffsets()
    19  	return s
    20  }
    21  
    22  func (s *Source) MarshalJSON() ([]byte, error) {
    23  	return json.Marshal(s.contents)
    24  }
    25  
    26  func (s *Source) UnmarshalJSON(b []byte) error {
    27  	contents := make([]rune, 0)
    28  	err := json.Unmarshal(b, &contents)
    29  	if err != nil {
    30  		return err
    31  	}
    32  
    33  	s.contents = contents
    34  	s.updateOffsets()
    35  	return nil
    36  }
    37  
    38  func (s *Source) Content() string {
    39  	return string(s.contents)
    40  }
    41  
    42  func (s *Source) Snippet(line int) (string, bool) {
    43  	charStart, found := s.findLineOffset(line)
    44  	if !found || len(s.contents) == 0 {
    45  		return "", false
    46  	}
    47  	charEnd, found := s.findLineOffset(line + 1)
    48  	if found {
    49  		return string(s.contents[charStart : charEnd-1]), true
    50  	}
    51  	return string(s.contents[charStart:]), true
    52  }
    53  
    54  // updateOffsets compute line offsets up front as they are referred to frequently.
    55  func (s *Source) updateOffsets() {
    56  	lines := strings.Split(string(s.contents), "\n")
    57  	offsets := make([]int32, len(lines))
    58  	var offset int32
    59  	for i, line := range lines {
    60  		offset = offset + int32(utf8.RuneCountInString(line)) + 1
    61  		offsets[int32(i)] = offset
    62  	}
    63  	s.lineOffsets = offsets
    64  }
    65  
    66  // findLineOffset returns the offset where the (1-indexed) line begins,
    67  // or false if line doesn't exist.
    68  func (s *Source) findLineOffset(line int) (int32, bool) {
    69  	if line == 1 {
    70  		return 0, true
    71  	} else if line > 1 && line <= len(s.lineOffsets) {
    72  		offset := s.lineOffsets[line-2]
    73  		return offset, true
    74  	}
    75  	return -1, false
    76  }