return count
}
+// A Line contains the data in bytes as well as a highlight state, match
+// and a flag for whether the highlighting needs to be updated
type Line struct {
data []byte
lines []Line
}
+// Append efficiently appends lines together
+// It allocates an additional 10000 lines if the original estimate
+// is incorrect
+func Append(slice []Line, data ...Line) []Line {
+ l := len(slice)
+ if l+len(data) > cap(slice) { // reallocate
+ newSlice := make([]Line, (l+len(data))+10000)
+ // The copy function is predeclared and works for any slice type.
+ copy(newSlice, slice)
+ slice = newSlice
+ }
+ slice = slice[0 : l+len(data)]
+ for i, c := range data {
+ slice[l+i] = c
+ }
+ return slice
+}
+
// NewLineArray returns a new line array from an array of bytes
-func NewLineArray(reader io.Reader) *LineArray {
+func NewLineArray(size int64, reader io.Reader) *LineArray {
la := new(LineArray)
+
+ la.lines = make([]Line, 0, 1000)
+
br := bufio.NewReader(reader)
+ var loaded int
- i := 0
+ n := 0
for {
data, err := br.ReadBytes('\n')
+ if len(data) > 1 && data[len(data)-2] == '\r' {
+ data = append(data[:len(data)-2], '\n')
+ if fileformat == 0 {
+ fileformat = 2
+ }
+ } else if len(data) > 0 {
+ if fileformat == 0 {
+ fileformat = 1
+ }
+ }
+
+ if n >= 1000 && loaded >= 0 {
+ totalLinesNum := int(float64(size) * (float64(n) / float64(loaded)))
+ newSlice := make([]Line, len(la.lines), totalLinesNum+10000)
+ // The copy function is predeclared and works for any slice type.
+ copy(newSlice, la.lines)
+ la.lines = newSlice
+ loaded = -1
+ }
+
+ if loaded >= 0 {
+ loaded += len(data)
+ }
+
if err != nil {
if err == io.EOF {
- la.lines = append(la.lines, Line{data[:len(data)], nil, nil, false})
+ la.lines = Append(la.lines, Line{data[:], nil, nil, false})
+ // la.lines = Append(la.lines, Line{data[:len(data)]})
}
// Last line was read
break
} else {
- la.lines = append(la.lines, Line{data[:len(data)-1], nil, nil, false})
+ // la.lines = Append(la.lines, Line{data[:len(data)-1]})
+ la.lines = Append(la.lines, Line{data[:len(data)-1], nil, nil, false})
}
- i++
+ n++
}
return la
return str
}
+// SaveString returns the string that should be written to disk when
+// the line array is saved
+// It is the same as string but uses crlf or lf line endings depending
+func (la *LineArray) SaveString(useCrlf bool) string {
+ str := ""
+ for i, l := range la.lines {
+ str += string(l.data)
+ if i != len(la.lines)-1 {
+ if useCrlf {
+ str += "\r"
+ }
+ str += "\n"
+ }
+ }
+ return str
+}
+
// NewlineBelow adds a newline below the given line number
func (la *LineArray) NewlineBelow(y int) {
la.lines = append(la.lines, Line{[]byte(" "), nil, nil, false})
return str
}
+// State gets the highlight state for the given line number
func (la *LineArray) State(lineN int) highlight.State {
return la.lines[lineN].state
}
+// SetState sets the highlight state at the given line number
func (la *LineArray) SetState(lineN int, s highlight.State) {
la.lines[lineN].state = s
}
+// SetMatch sets the match at the given line number
func (la *LineArray) SetMatch(lineN int, m highlight.LineMatch) {
la.lines[lineN].match = m
}
+// Match retrieves the match for the given line number
func (la *LineArray) Match(lineN int) highlight.LineMatch {
return la.lines[lineN].match
}